diff --git a/db/migrations/5.3.11_courseware_cron_events.php b/db/migrations/5.3.11_courseware_cron_events.php
new file mode 100644
index 0000000000000000000000000000000000000000..48dbfcf130a18627dd70f2db755144ea6bd27efb
--- /dev/null
+++ b/db/migrations/5.3.11_courseware_cron_events.php
@@ -0,0 +1,49 @@
+<?php
+
+require_once('lib/cronjobs/courseware.php');
+
+class CoursewareCronEvents extends Migration
+{
+    public function description()
+    {
+        return 'Prepares database tables for storing timestamps of courseware cron events, ' .
+            'like certificate sending and reminders.';
+    }
+
+    public function up()
+    {
+        // Create a table for certificates
+        DBManager::get()->exec("CREATE TABLE IF NOT EXISTS `cw_certificates` (
+            `id` CHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
+            `user_id` CHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
+            `course_id` CHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
+            `mkdate` INT(11) NOT NULL,
+            PRIMARY KEY (`id`),
+            INDEX index_user_id (`user_id`),
+            INDEX index_course_id (`course_id`),
+            INDEX index_user_ourse (`user_id`, `course_id`)
+        )");
+
+        CoursewareCronjob::register()->schedulePeriodic(41, 1)->activate();
+    }
+
+    public function down()
+    {
+        CoursewareCronjob::unregister();
+
+        DBManager::get()->exec("DROP TABLE IF EXISTS `cw_certificates`");
+
+        $fields = [
+            'COURSEWARE_CERTIFICATE_SETTINGS',
+            'COURSEWARE_REMINDER_SETTINGS',
+            'COURSEWARE_RESET_PROGRESS_SETTINGS',
+            'COURSEWARE_LAST_REMINDER',
+            'COURSEWARE_LAST_PROGRESS_RESET'
+        ];
+        DBManager::get()->execute("DELETE FROM `config` WHERE `field` IN (:fields)",
+            ['fields' => $fields]);
+        DBManager::get()->execute("DELETE FROM `config_values` WHERE `field` IN (:fields)",
+            ['fields' => $fields]);
+    }
+
+}
diff --git a/lib/classes/CoursewarePDFCertificate.php b/lib/classes/CoursewarePDFCertificate.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3ef02f70bb92de223faf95f18010466185447ef
--- /dev/null
+++ b/lib/classes/CoursewarePDFCertificate.php
@@ -0,0 +1,40 @@
+<?php
+
+class CoursewarePDFCertificate extends TCPDF
+{
+    public function __construct($background = false, $orientation = 'P', $unit = 'mm', $format = 'A4', $unicode = true, $encoding = 'UTF-8')
+    {
+        $this->config = Config::get();
+        if ($this->config->getValue('LOAD_EXTERNAL_MEDIA') === 'proxy') {
+            $this->media_proxy = new MediaProxy();
+        }
+        parent::__construct($orientation, $unit, $format, $unicode, $encoding, false);
+        if ($background) {
+            $fileRef = FileRef::find($background);
+            $this->background = $fileRef->file->getPath();
+        } else {
+            $this->background = $GLOBALS['STUDIP_BASE_PATH'] . '/public/assets/images/pdf/pdf_default_background.jpg';
+        }
+
+        $this->setDefaults();
+    }
+
+    public function Header()
+    {
+        $bMargin = $this->getBreakMargin();
+        $auto_page_break = $this->AutoPageBreak;
+        $this->SetAutoPageBreak(false, 0);
+        $this->Image($this->background, 0, 0, 210, 297, '', '', '', false, 300, '', false, false, 0);
+        $this->setFont('helvetica', 'B', 50);
+        $this->Cell(0, 160, 'Z E R T I F I K A T', 0, false, 'C', 0, '', 0, false, 'T', 'M');
+        $this->SetAutoPageBreak($auto_page_break, $bMargin);
+        $this->setPageMark();
+    }
+
+    private function setDefaults()
+    {
+        $this->SetTopMargin(110);
+        $this->SetLeftMargin(20);
+        $this->SetRightMargin(20);
+    }
+}
diff --git a/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php b/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php
index 965e3b64980b6cc9f44d55c369880b0e65a3b2a7..2b70cbf90b605d4f98bdece4714142aa47193e26 100644
--- a/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php
+++ b/lib/classes/JsonApi/Routes/Courseware/CoursewareInstancesUpdate.php
@@ -78,6 +78,30 @@ class CoursewareInstancesUpdate extends JsonApiController
                 return 'Attribute `editing-permission-level` contains an invalid value.';
             }
         }
+
+        if (self::arrayHas($json, 'data.attributes.certificate-settings')) {
+            $certificateSettings = self::arrayGet($json, 'data.attributes.certificate-settings');
+
+            if (!$resource->isValidCertificateSettings($certificateSettings)) {
+                return 'Attribute `certificate-settings` contains an invalid value.';
+            }
+        }
+
+        if (self::arrayHas($json, 'data.attributes.reminder-settings')) {
+            $reminderSettings = self::arrayGet($json, 'data.attributes.reminder-settings');
+
+            if (!$resource->isValidReminderSettings($reminderSettings)) {
+                return 'Attribute `reminder-settings` contains an invalid value.';
+            }
+        }
+
+        if (self::arrayHas($json, 'data.attributes.reset-progress-settings')) {
+            $resetProgressSettings = self::arrayGet($json, 'data.attributes.reset-progress-settings');
+
+            if (!$resource->isValidResetProgressSettings($resetProgressSettings)) {
+                return 'Attribute `reset-progress-settings` contains an invalid value.';
+            }
+        }
     }
 
     private function updateInstance(\User $user, Instance $instance, array $json): Instance
@@ -95,6 +119,15 @@ class CoursewareInstancesUpdate extends JsonApiController
         $editingPermissionLevel = $get('data.attributes.editing-permission-level');
         $instance->setEditingPermissionLevel($editingPermissionLevel);
 
+        $certificateSettings = $get('data.attributes.certificate-settings');
+        $instance->setCertificateSettings($certificateSettings);
+
+        $reminderSettings = $get('data.attributes.reminder-settings');
+        $instance->setReminderSettings($reminderSettings);
+
+        $resetProgressSettings = $get('data.attributes.reset-progress-settings');
+        $instance->setResetProgressSettings($resetProgressSettings);
+
         return $instance;
     }
 }
diff --git a/lib/classes/JsonApi/Schemas/Courseware/Instance.php b/lib/classes/JsonApi/Schemas/Courseware/Instance.php
index 055c387defd8ca4e76ea3ad55cbecf062cb8a056..63a4d950b831a2d6818a855b221aa29add7c889e 100644
--- a/lib/classes/JsonApi/Schemas/Courseware/Instance.php
+++ b/lib/classes/JsonApi/Schemas/Courseware/Instance.php
@@ -36,6 +36,9 @@ class Instance extends SchemaProvider
             'favorite-block-types' => $resource->getFavoriteBlockTypes($user),
             'sequential-progression' => (bool) $resource->getSequentialProgression(),
             'editing-permission-level' => $resource->getEditingPermissionLevel(),
+            'certificate-settings' => $resource->getCertificateSettings(),
+            'reminder-settings' => $resource->getReminderSettings(),
+            'reset-progress-settings' => $resource->getResetProgressSettings()
         ];
     }
 
diff --git a/lib/cronjobs/courseware.php b/lib/cronjobs/courseware.php
new file mode 100644
index 0000000000000000000000000000000000000000..16e0ad96475180150386cb3696cb5123135a6e69
--- /dev/null
+++ b/lib/cronjobs/courseware.php
@@ -0,0 +1,341 @@
+<?php
+/**
+ * courseware.php
+ *
+ * @author Thomas Hackl <hackl@data-quest.de>
+ * @access public
+ * @since  5.3
+ */
+
+class CoursewareCronjob extends CronJob
+{
+    public static function getName()
+    {
+        return _('Courseware-Erinnerungen und -zertifikate verschicken sowie Fortschritt zurücksetzen');
+    }
+
+    public static function getDescription()
+    {
+        return _('Versendet Erinnerungen, Zertifikate bei Erreichen eines bestimmten Fortschritts und setzt ' .
+            'Fortschritt bei derartig konfigurierten Coursewares zurück.');
+    }
+
+    public static function getParameters()
+    {
+        return [
+            'verbose' => [
+                'type'        => 'boolean',
+                'default'     => false,
+                'status'      => 'optional',
+                'description' => _('Sollen Ausgaben erzeugt werden (sind später im Log des Cronjobs sichtbar)'),
+            ]
+        ];
+    }
+
+    public function setUp()
+    {
+    }
+
+    public function execute($last_result, $parameters = [])
+    {
+        $verbose = $parameters['verbose'];
+
+        /*
+         * Fetch all courses that have some relevant settings.
+         */
+        $todo = DBManager::get()->fetchAll(
+            "SELECT c.`range_id`, c. `field`, c.`value`
+            FROM `config_values` c
+                JOIN `seminare` s ON (s.`Seminar_id` = c.`range_id`)
+            WHERE c.`field` IN (:fields)",
+            ['fields' => [
+                // Send certificate when this progress is reached
+                'COURSEWARE_CERTIFICATE_SETTINGS',
+                // Remind all users about courseware
+                'COURSEWARE_REMINDER_SETTINGS',
+                // Reset user progress to 0
+                'COURSEWARE_RESET_PROGRESS_SETTINGS'
+            ]
+            ]
+        );
+
+        if (count($todo) > 0) {
+
+            if ($verbose) {
+                echo sprintf("Found %u courses to process.\n", count($todo));
+            }
+
+            $timezone = Config::get()->DEFAULT_TIMEZONE;
+
+            // Process all found entries...
+            foreach ($todo as $one) {
+
+                // Fetch all courseware blocks belonging to the current course.
+                $blocks = DBManager::get()->fetchFirst(
+                    "SELECT DISTINCT b.`id`
+                            FROM `cw_blocks` b
+                                JOIN `cw_containers` c ON (c.`id` = b.`container_id`)
+                                JOIN `cw_structural_elements` e ON (e.`id` = c.`structural_element_id`)
+                            WHERE e.`range_id` = :course",
+                    ['course' => $one['range_id']]
+                );
+
+                // extract details from JSON
+                $settings = json_decode($one['value'], true);
+
+                // differentiate by setting type
+                switch ($one['field']) {
+                    // Send certificates to those who have progressed far enough and have not yet gotten one.
+                    case 'COURSEWARE_CERTIFICATE_SETTINGS':
+
+                        if ($verbose) {
+                            echo sprintf("Generating certificates for course %s.\n",
+                                $one['range_id']);
+                        }
+
+                        // Fetch accumulated progress values for all users in this course.
+                        $progresses = DBManager::get()->fetchAll(
+                            "SELECT DISTINCT p.`user_id`, SUM(p.`grade`) AS progress
+                            FROM `cw_user_progresses` p
+                            WHERE `block_id` IN (:blocks)
+                                AND NOT EXISTS (
+                                    SELECT `id` FROM `cw_certificates` WHERE `user_id` = p.`user_id` AND `course_id` = :course
+                                )
+                            GROUP BY `user_id`",
+                            ['blocks' => $blocks, 'course' => $one['range_id']]
+                        );
+
+                        // Calculate percentual progress and send certificates if necessary.
+                        foreach ($progresses as $progress) {
+                            $percent = ($progress['progress'] / count($blocks)) * 100;
+                            if ($percent >= $settings['threshold']) {
+                                if ($verbose) {
+                                    echo sprintf("User %s will get a certificate for course %s.\n",
+                                        $progress['user_id'], $one['range_id']);
+                                }
+
+                                $this->sendCertificate($one['range_id'], $progress['user_id'],
+                                    $percent, $settings);
+
+                                /*
+                                 * Insert a new entry into database for tracking who already got a certificate.
+                                 * This can be useful if certificates get a validity time or such.
+                                 */
+                                $entry = new Courseware\Certificate();
+                                $entry->user_id = $progress['user_id'];
+                                $entry->course_id = $one['range_id'];
+                                $entry->store();
+                            }
+                        }
+
+                        break;
+
+                    // Send reminders to all course participants.
+                    case 'COURSEWARE_REMINDER_SETTINGS':
+
+                        // Check when the last reminder was sent...
+                        $now = new DateTime('', new DateTimeZone($timezone));
+
+                        // What would be the minimum date for the last reminder?
+                        $minReminder = clone $now;
+
+                        // The last reminder has been sent at?
+                        $lastReminder = new DateTime('', new DateTimeZone($timezone));
+                        $lastReminder->setTimestamp(
+                            UserConfig::get($one['range_id'])->COURSEWARE_LAST_REMINDER ?: 0
+                        );
+
+                        // Check if the settings specify a start and/or end date for reminders
+                        $start = new DateTime($settings['startDate'] ?: '1970-01-01',
+                            new DateTimeZone($timezone));
+                        $end = new DateTime($settings['endDate'] ?: '2199-12-31',
+                            new DateTimeZone($timezone));
+
+                        $interval = new DateInterval('P1D');
+                        switch ($settings['interval']) {
+                            case 7:
+                                $interval = new DateInterval('P7D');
+                                break;
+                            case 14:
+                                $interval = new DateInterval('P14D');
+                                break;
+                            case 30:
+                                $interval = new DateInterval('P1M');
+                                break;
+                            case 90:
+                                $interval = new DateInterval('P3M');
+                                break;
+                            case 180:
+                                $interval = new DateInterval('P6M');
+                                break;
+                            case 365:
+                                $interval = new DateInterval('P1Y');
+                                break;
+                        }
+                        $minReminder->sub($interval);
+
+                        // ... and send a new one if necessary.
+                        if ($lastReminder <= $minReminder && $now >= $start && $now <= $end) {
+                            if ($verbose) {
+                                echo sprintf("Sending reminders for course %s.\n",
+                                    $one['range_id']);
+                            }
+
+                            if ($this->sendReminders($one['range_id'], $settings)) {
+                                UserConfig::get($one['range_id'])->store('COURSEWARE_LAST_REMINDER',
+                                    $now->getTimestamp()
+                                );
+                            }
+                        }
+
+                        break;
+
+                    // Reset courseware progress to 0 for all course participants.
+                    case 'COURSEWARE_RESET_PROGRESS_SETTINGS':
+
+                        // Check when the last reset was performed...
+                        $now = new DateTime('', new DateTimeZone($timezone));
+                        $checkLast = clone $now;
+                        $lastReset = new DateTime('', new DateTimeZone($timezone));
+                        $lastReset->setTimestamp(
+                            UserConfig::get($one['range_id'])->COURSEWARE_LAST_PROGRESS_RESET ?: 0
+                        );
+
+                        $interval = new DateInterval('P1D');
+                        switch ($one['value']) {
+                            case 14:
+                                $interval = new DateInterval('P14D');
+                                break;
+                            case 30:
+                                $interval = new DateInterval('P1M');
+                                break;
+                            case 90:
+                                $interval = new DateInterval('P3M');
+                                break;
+                            case 180:
+                                $interval = new DateInterval('P6M');
+                                break;
+                            case 365:
+                                $interval = new DateInterval('P1Y');
+                                break;
+                        }
+
+                        // ... and reset again if necessary.
+                        if ($lastReset <= $checkLast->sub($interval)) {
+                            if ($verbose) {
+                                echo sprintf("Resetting all progress for courseware in course %s.\n",
+                                    $one['range_id']);
+                            }
+
+                            // Remove all progress in the given blocks.
+                            $this->resetProgress($one['range_id'], $blocks, $settings);
+
+                            UserConfig::get($one['range_id'])->store('COURSEWARE_LAST_PROGRESS_RESET',
+                                $now->getTimestamp()
+                            );
+                        }
+                }
+            }
+
+        } else if ($verbose) {
+            echo "Nothing to do.\n";
+        }
+    }
+
+    private function sendCertificate($course_id, $user_id, $progress, $settings)
+    {
+        $user = User::find($user_id);
+        $course = Course::find($course_id);
+
+        $template = $GLOBALS['template_factory']->open('courseware/mails/certificate');
+        $html = $template->render(
+            compact('user', 'course')
+        );
+
+        // Generate the PDF.
+        $pdf = new CoursewarePDFCertificate($settings['image']);
+        $pdf->AddPage();
+        $pdf->writeHTML($html, true, false, true, false, '');
+        $pdf_file_name = $user->nachname . '_' . $course->name . '_' . _('Zertifikat') . '.pdf';
+        $filename = $GLOBALS['TMP_PATH'] . '/' . $pdf_file_name;
+        $pdf->Output($filename, 'F');
+
+        // Send the mail with PDF attached.
+        $mail = new StudipMail();
+
+        $message = sprintf(
+            _('Anbei erhalten Sie Ihr Courseware-Zertifikat zur Veranstaltung %1$s, in der Sie einen Fortschritt ' .
+                'von %2$u %% erreicht haben.'), $course->getFullname(), $progress);
+        $message .= "\n\n" . _('Ãœber folgenden Link kommen Sie direkt zur Courseware') . ': ' .
+            URLHelper::getURL('seminar_main.php', ['auswahl' => $course->id,
+                'redirect_to' => 'dispatch.php/course/courseware']);
+
+        $mail->addRecipient($user->email, $user->getFullname())
+            ->setSubject(_('Courseware: Zertifikat') . ' - ' . $course->getFullname())
+            ->setBodyText($message)
+            ->addFileAttachment($filename, $pdf_file_name)
+            ->send();
+
+        @unlink($filename);
+
+        // Add database entry for the certificate.
+
+    }
+
+    private function sendReminders($course_id, $settings)
+    {
+        $course = Course::find($course_id);
+
+        $recipients = $course->getMembersWithStatus('autor', true);
+
+        $mail = new StudipMail();
+
+        foreach ($recipients as $rec) {
+            $mail->addRecipient(
+                $rec->email,
+                $rec->getUserFullname(),
+                'bcc'
+            );
+        }
+
+        $message = $settings['mailText'] . "\n\n" . _('Ãœber folgenden Link kommen Sie direkt zur Courseware') . ': ' .
+            URLHelper::getURL('seminar_main.php', ['auswahl' => $course->id,
+                'redirect_to' => 'dispatch.php/course/courseware']);
+
+        $mail->setSubject(_('Courseware: Erinnerung') . ' - ' . $course->getFullname())
+            ->setBodyText($message);
+
+        return $mail->send();
+    }
+
+    private function resetProgress($course_id, $block_ids, $settings)
+    {
+        $course = Course::find($course_id);
+
+        DBManager::get()->execute(
+            "DELETE FROM `cw_user_progresses` WHERE `block_id` IN (:blocks)",
+            ['blocks' => $block_ids]
+        );
+
+        $recipients = $course->getMembersWithStatus('autor', true);
+
+        $mail = new StudipMail();
+
+        foreach ($recipients as $rec) {
+            $mail->addRecipient(
+                $rec->email,
+                $rec->getUserFullname(),
+                'bcc'
+            );
+        }
+
+        $message = $settings['mailText'] . "\n\n" . _('Ãœber folgenden Link kommen Sie direkt zur Courseware') . ': ' .
+            URLHelper::getURL('seminar_main.php', ['auswahl' => $course->id,
+                'redirect_to' => 'dispatch.php/course/courseware']);
+
+        $mail->setSubject(_('Courseware: Fortschritt zurückgesetzt') . ' - ' . $course->getFullname())
+            ->setBodyText($message);
+
+        return $mail->send();
+    }
+}
diff --git a/lib/models/Courseware/Certificate.php b/lib/models/Courseware/Certificate.php
new file mode 100644
index 0000000000000000000000000000000000000000..d0c9fd9a5e11bccc1857047ffe8eb915de04c4f7
--- /dev/null
+++ b/lib/models/Courseware/Certificate.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Courseware;
+
+use \User, \Course;
+
+/**
+ * Courseware's certificates.
+ *
+ * @author  Thomas Hackl <hackl@data-quest.de>
+ * @license GPL2 or any later version
+ *
+ * @since   Stud.IP 5.3
+ *
+ * @property string     $id             database column
+ * @property string     $user_id        database column
+ * @property string     $course_id      database column
+ * @property int        $mkdate         database column
+ */
+class Certificate extends \SimpleORMap
+{
+    protected static function configure($config = [])
+    {
+        $config['db_table'] = 'cw_certificates';
+
+        $config['belongs_to']['user'] = [
+            'class_name' => User::class,
+            'foreign_key' => 'user_id',
+        ];
+
+        $config['belongs_to']['course'] = [
+            'class_name' => Course::class,
+            'foreign_key' => 'course_id',
+        ];
+
+        parent::configure($config);
+    }
+
+}
diff --git a/lib/models/Courseware/Instance.php b/lib/models/Courseware/Instance.php
index c823a4edbde736d52530cb77e140ea798e1cad92..0b388fe93ca2db2c340ded696361f95cf2d2fbb3 100644
--- a/lib/models/Courseware/Instance.php
+++ b/lib/models/Courseware/Instance.php
@@ -231,6 +231,161 @@ class Instance
         }
     }
 
+
+    /**
+     * Returns the certificate creation settings.
+     *
+     * @return array
+     */
+    public function getCertificateSettings(): array
+    {
+        $range = $this->getRange();
+        /** @var array $certificateSettings */
+        $certificateSettings = json_decode(
+            $range->getConfiguration()->getValue('COURSEWARE_CERTIFICATE_SETTINGS'),
+            true
+        )?: [];
+        $this->validateCertificateSettings($certificateSettings);
+
+        return $certificateSettings;
+    }
+
+    /**
+     * Sets the certificate settings for this courseware instance.
+     *
+     * @param array $certificateSettings an array of parameters
+     */
+    public function setCertificateSettings(array $certificateSettings): void
+    {
+        $this->validateCertificateSettings($certificateSettings);
+        $range = $this->getRange();
+        $range->getConfiguration()->store('COURSEWARE_CERTIFICATE_SETTINGS',
+            count($certificateSettings) > 0 ? json_encode($certificateSettings) : null);
+    }
+
+    /**
+     * Validates certificate settings.
+     *
+     * @param array $certificateSettings settings for certificate creation
+     *
+     * @return bool true if all given values are valid, false otherwise
+     */
+    public function isValidCertificateSettings(array $certificateSettings): bool
+    {
+        return (int) $certificateSettings['threshold'] >= 0 && (int) $certificateSettings['threshold'] <= 100;
+    }
+
+    private function validateCertificateSettings(array $certificateSettings): void
+    {
+        if (!$this->isValidCertificateSettings($certificateSettings)) {
+            throw new \InvalidArgumentException('Invalid certificate settings given.');
+        }
+    }
+
+    /**
+     * Returns the reminder message sending settings.
+     *
+     * @return array
+     */
+    public function getReminderSettings(): array
+    {
+        $range = $this->getRange();
+        /** @var int $reminderInterval */
+        $reminderSettings = json_decode(
+            $range->getConfiguration()->getValue('COURSEWARE_REMINDER_SETTINGS'),
+            true
+        )?: [];
+        $this->validateReminderSettings($reminderSettings);
+
+        return $reminderSettings;
+    }
+
+    /**
+     * Sets the reminder message settings this courseware instance.
+     *
+     * @param array $reminderSettings an array of parameters
+     */
+    public function setReminderSettings(array $reminderSettings): void
+    {
+        $this->validateReminderSettings($reminderSettings);
+        $range = $this->getRange();
+        $range->getConfiguration()->store('COURSEWARE_REMINDER_SETTINGS',
+            count($reminderSettings) > 0 ? json_encode($reminderSettings) : null);
+    }
+
+    /**
+     * Validates reminder message settings.
+     *
+     * @param array $reminderSettings settings for reminder mail sending
+     *
+     * @return bool true if all given values are valid, false otherwise
+     */
+    public function isValidReminderSettings(array $reminderSettings): bool
+    {
+        $valid = in_array($reminderSettings['interval'], [0, 7, 14, 30, 90, 180, 365]);
+
+        return $valid;
+    }
+
+    private function validateReminderSettings(array $reminderSettings): void
+    {
+        if (!$this->isValidReminderSettings($reminderSettings)) {
+            throw new \InvalidArgumentException('Invalid reminder settings given.');
+        }
+    }
+
+    /**
+     * Returns the progress resetting settings.
+     *
+     * @return array
+     */
+    public function getResetProgressSettings(): array
+    {
+        $range = $this->getRange();
+        /** @var int $reminderInterval */
+        $resetProgressSettings = json_decode(
+            $range->getConfiguration()->getValue('COURSEWARE_RESET_PROGRESS_SETTINGS'),
+            true
+        )?: [];
+        $this->validateResetProgressSettings($resetProgressSettings);
+
+        return $resetProgressSettings;
+    }
+
+    /**
+     * Sets the progress resetting settings this courseware instance.
+     *
+     * @param array $reminderSettings an array of parameters
+     */
+    public function setResetProgressSettings(array $resetProgressSettings): void
+    {
+        $this->validateResetProgressSettings($resetProgressSettings);
+        $range = $this->getRange();
+        $range->getConfiguration()->store('COURSEWARE_RESET_PROGRESS_SETTINGS',
+            count($resetProgressSettings) > 0 ? json_encode($resetProgressSettings) : null);
+    }
+
+    /**
+     * Validates progress resetting settings.
+     *
+     * @param array $resetProgressSettings settings for progress resetting
+     *
+     * @return bool true if all given values are valid, false otherwise
+     */
+    public function isValidResetProgressSettings(array $resetProgressSettings): bool
+    {
+        $valid = in_array($resetProgressSettings['interval'], [0, 14, 30, 90, 180, 365]);
+
+        return $valid;
+    }
+
+    private function validateResetProgressSettings(array $resetProgressSettings): void
+    {
+        if (!$this->isValidResetProgressSettings($resetProgressSettings)) {
+            throw new \InvalidArgumentException('Invalid progress resetting settings given.');
+        }
+    }
+
     /**
      * Returns all bookmarks of a user associated to this courseware instance.
      *
diff --git a/public/assets/images/pdf/pdf_default_background.jpg b/public/assets/images/pdf/pdf_default_background.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..e91edda46beb097e11b4bc1f64eaf0e71029dd53
Binary files /dev/null and b/public/assets/images/pdf/pdf_default_background.jpg differ
diff --git a/resources/vue/components/courseware/CoursewareToolsAdmin.vue b/resources/vue/components/courseware/CoursewareToolsAdmin.vue
index 337a39e47fe03682e33ae990297bb8636d3854e7..974e6fbbf8da495b042ddc4fd68f1be72e535338 100644
--- a/resources/vue/components/courseware/CoursewareToolsAdmin.vue
+++ b/resources/vue/components/courseware/CoursewareToolsAdmin.vue
@@ -2,37 +2,195 @@
     <div class="cw-tools cw-tools-admin">
         <form class="default" @submit.prevent="">
             <fieldset>
-                <legend><translate>Allgemeine Einstellungen</translate></legend>
+                <legend>{{ $gettext('Allgemeine Einstellungen') }}</legend>
                 <label>
-                    <span><translate>Art der Inhaltsabfolge</translate></span>
+                    <span>{{ $gettext('Art der Inhaltsabfolge') }}</span>
                     <select class="size-s" v-model="currentProgression">
-                        <option value="0"><translate>Frei</translate></option>
-                        <option value="1"><translate>Sequentiell</translate></option>
+                        <option value="0">{{ $gettext('Frei') }}</option>
+                        <option value="1">{{ $gettext('Sequentiell') }}</option>
                     </select>
                 </label>
 
                 <label>
-                    <span><translate>Editierberechtigung für Tutor/-innen</translate></span>
+                    <span>{{ $gettext('Editierberechtigung für Tutor/-innen') }}</span>
                     <select class="size-s" v-model="currentPermissionLevel">
-                        <option value="dozent"><translate>Nein</translate></option>
-                        <option value="tutor"><translate>Ja</translate></option>
+                        <option value="dozent">{{ $gettext('Nein') }}</option>
+                        <option value="tutor">{{ $gettext('Ja') }}</option>
                     </select>
                 </label>
             </fieldset>
+            <fieldset>
+                <legend>
+                    {{ $gettext('Zertifikate') }}
+                </legend>
+                <label>
+                    <input type="checkbox" name="makecert" v-model="makeCert">
+                    <span>
+                        {{ $gettext('Zertifikat bei Erreichen einer Fortschrittsgrenze versenden') }}
+                    </span>
+                    <studip-tooltip-icon :text="$gettext('Erreicht eine Person in diesem Lernmaterial den ' +
+                        'hier eingestellten Fortschritt, so erhält Sie ein PDF-Zertifikat per E-Mail.')"/>
+                </label>
+                <label v-if="makeCert">
+                    <span>
+                        {{ $gettext('Erforderlicher Fortschritt (in Prozent), um ein Zertifikat zu erhalten') }}
+                    </span>
+                    <input type="number" min="1" max="100" name="threshold" v-model="certThreshold">
+                </label>
+                <label v-if="makeCert">
+                    <span>
+                        {{ $gettext('Hintergrundbild des Zertifikats wählen') }}
+                    </span>
+                    <courseware-file-chooser :isImage="true" v-model="certImage"
+                                             @selectFile="updateCertImage"></courseware-file-chooser>
+                </label>
+            </fieldset>
+            <fieldset>
+                <legend>
+                    {{ $gettext('Erinnerungen') }}
+                </legend>
+                <label>
+                    <input type="checkbox" name="sendreminders" v-model="sendReminders">
+                    <span>
+                        {{ $gettext('Erinnerungsnachrichten an alle Teilnehmenden schicken') }}
+                    </span>
+                    <studip-tooltip-icon :text="$gettext('Hier können periodisch Nachrichten an alle ' +
+                    'Teilnehmenden verschickt werden, um z.B. an die Bearbeitung dieses Lernmaterials zu erinnern.')"/>
+                </label>
+
+                <label v-if="sendReminders">
+                    <span>
+                        {{ $gettext('Zeitraum zwischen Erinnerungen') }}
+                    </span>
+                    <select name="reminder_interval" v-model="reminderInterval">
+                        <option value="7">
+                            {{ $gettext('wöchentlich') }}
+                        </option>
+                        <option value="14">
+                            {{ $gettext('14-tägig') }}
+                        </option>
+                        <option value="30">
+                            {{ $gettext('monatlich') }}
+                        </option>
+                        <option value="90">
+                            {{ $gettext('vierteljährlich') }}
+                        </option>
+                        <option value="180">
+                            {{ $gettext('halbjährlich') }}
+                        </option>
+                        <option value="365">
+                            {{ $gettext('jährlich') }}
+                        </option>
+                    </select>
+                </label>
+                <label v-if="sendReminders" class="col-3">
+                    <span>
+                        {{ $gettext('Erstmalige Erinnerung am') }}
+                        <input type="date" name="reminder_start_date"
+                               v-model="reminderStartDate">
+                    </span>
+                </label>
+                <label v-if="sendReminders" class="col-3">
+                    <span>
+                        {{ $gettext('Letztmalige Erinnerung am') }}
+                        <input type="date" name="reminder_end_date"
+                               v-model="reminderEndDate">
+                    </span>
+                </label>
+                <label v-if="sendReminders">
+                    <span>
+                        {{ $gettext('Text der Erinnerungsmail') }}
+                        <textarea cols="70" rows="4" name="reminder_mail_text" data-editor="minimal"
+                                  v-model="reminderMailText"></textarea>
+                    </span>
+                </label>
+            </fieldset>
+            <fieldset>
+                <legend>
+                    {{ $gettext('Fortschritt') }}
+                </legend>
+                <label>
+                    <input type="checkbox" name="resetprogress" v-model="resetProgress">
+                    <span>
+                        {{ $gettext('Fortschritt periodisch auf 0 zurücksetzen') }}
+                    </span>
+                    <studip-tooltip-icon :text="$gettext('Hier kann eingestellt werden, den Fortschritt ' +
+                        'aller Teilnehmenden periodisch auf 0 zurückzusetzen.')"/>
+                </label>
+                <label v-if="resetProgress">
+                    <span>
+                        {{ $gettext('Zeitraum zum Rücksetzen des Fortschritts') }}
+                    </span>
+                    <select name="reset_progress_interval" v-model="resetProgressInterval">
+                        <option value="14">
+                            {{ $gettext('14-tägig') }}
+                        </option>
+                        <option value="30">
+                            {{ $gettext('monatlich') }}
+                        </option>
+                        <option value="90">
+                            {{ $gettext('vierteljährlich') }}
+                        </option>
+                        <option value="180">
+                            {{ $gettext('halbjährlich') }}
+                        </option>
+                        <option value="365">
+                            {{ $gettext('jährlich') }}
+                        </option>
+                    </select>
+                </label>
+                <label v-if="resetProgress" class="col-3">
+                    <span>
+                        {{ $gettext('Erstmaliges Zurücksetzen am') }}
+                        <input type="date" dataformatas="" name="reset_progress_start_date"
+                               v-model="resetProgressStartDate">
+                    </span>
+                </label>
+                <label v-if="resetProgress" class="col-3">
+                    <span>
+                        {{ $gettext('Letztmaliges Zurücksetzen am') }}
+                        <input type="date" name="reset_progress_end_date"
+                               v-model="resetProgressEndDate">
+                    </span>
+                </label>
+                <label v-if="resetProgress">
+                    <span>
+                        {{ $gettext('Text der Rücksetzungsmail') }}
+                        <textarea cols="70" rows="4" name="reset_progress_mail_text" data-editor="minimal"
+                                  v-model="resetProgressMailText"></textarea>
+                    </span>
+                </label>
+            </fieldset>
         </form>
-        <button class="button" @click="store"><translate>Ãœbernehmen</translate></button>
+        <button class="button" @click="store">{{ $gettext('Ãœbernehmen') }}</button>
     </div>
 </template>
 
 <script>
 import { mapActions, mapGetters } from 'vuex';
+import CoursewareFileChooser from "./CoursewareFileChooser.vue";
+import StudipTooltipIcon from '../StudipTooltipIcon.vue';
 
 export default {
     name: 'cw-tools-admin',
+    components: { StudipTooltipIcon, CoursewareFileChooser },
     data() {
         return {
             currentPermissionLevel: '',
             currentProgression: '',
+            makeCert: false,
+            certThreshold: 0,
+            certImage: '',
+            sendReminders: false,
+            reminderInterval: 7,
+            reminderStartDate: '',
+            reminderEndDate: '',
+            reminderMailText: '',
+            resetProgress: false,
+            resetProgressInterval: 180,
+            resetProgressStartDate: '',
+            resetProgressEndDate: '',
+            resetProgressMailText: ''
         };
     },
     computed: {
@@ -46,8 +204,28 @@ export default {
             companionSuccess: 'companionSuccess',
         }),
         initData() {
+            console.log(this.courseware.attributes);
             this.currentPermissionLevel = this.courseware.attributes['editing-permission-level'];
             this.currentProgression = this.courseware.attributes['sequential-progression'] ? '1' : '0';
+            this.certSettings = this.courseware.attributes['certificate-settings'];
+            this.makeCert = typeof(this.certSettings) === 'object' &&
+                Object.keys(this.certSettings).length > 0;
+            this.certThreshold = this.certSettings.threshold;
+            this.certImage = this.certSettings.image;
+            this.reminderSettings = this.courseware.attributes['reminder-settings'];
+            this.sendReminders = typeof(this.reminderSettings) === 'object' &&
+                Object.keys(this.reminderSettings).length > 0;
+            this.reminderInterval = this.reminderSettings.interval;
+            this.reminderStartDate = this.reminderSettings.startDate;
+            this.reminderEndDate = this.reminderSettings.endDate;
+            this.reminderMailText = this.reminderSettings.mailText;
+            this.resetProgressSettings = this.courseware.attributes['reset-progress-settings'];
+            this.resetProgress = typeof(this.resetProgressSettings) === 'object' &&
+                Object.keys(this.resetProgressSettings).length > 0;
+            this.resetProgressInterval = this.resetProgressSettings.interval;
+            this.resetProgressStartDate = this.resetProgressSettings.startDate;
+            this.resetProgressEndDate = this.resetProgressSettings.endDate;
+            this.resetProgressMailText = this.resetProgressSettings.mailText;
         },
         store() {
             this.companionSuccess({
@@ -56,8 +234,36 @@ export default {
             this.storeCoursewareSettings({
                 permission: this.currentPermissionLevel,
                 progression: this.currentProgression,
+                certificateSettings: this.generateCertificateSettings(),
+                reminderSettings: this.generateReminderSettings(),
+                resetProgressSettings: this.generateResetProgressSettings()
             });
         },
+        generateCertificateSettings() {
+            return this.makeCert ? {
+                threshold: this.certThreshold,
+                image: this.certImage
+            } : {};
+        },
+        generateReminderSettings() {
+            return this.sendReminders ? {
+                interval: this.reminderInterval,
+                startDate: this.reminderStartDate,
+                endDate: this.reminderEndDate,
+                mailText: this.reminderMailText
+            } : {};
+        },
+        generateResetProgressSettings() {
+            return this.resetProgress ? {
+                interval: this.resetProgressInterval,
+                startDate: this.resetProgressStartDate,
+                endDate: this.resetProgressEndDate,
+                mailText: this.resetProgressMailText
+            } : {};
+        },
+        updateCertImage(file) {
+            this.certImage = file.id;
+        }
     },
     mounted() {
         this.initData();
diff --git a/resources/vue/store/courseware/courseware.module.js b/resources/vue/store/courseware/courseware.module.js
index 1380ea008dbd508af62da3ee272d5e2d504a9dd6..e6e14acea08abe6e238744e64b1dc40539638675 100644
--- a/resources/vue/store/courseware/courseware.module.js
+++ b/resources/vue/store/courseware/courseware.module.js
@@ -536,10 +536,15 @@ export const actions = {
         return dispatch('loadContainer', containerId);
     },
 
-    async storeCoursewareSettings({ dispatch, getters }, { permission, progression }) {
+    async storeCoursewareSettings({ dispatch, getters },
+                                  { permission, progression, certificateSettings, reminderSettings,
+                                      resetProgressSettings }) {
         const courseware = getters.courseware;
         courseware.attributes['editing-permission-level'] = permission;
         courseware.attributes['sequential-progression'] = progression;
+        courseware.attributes['certificate-settings'] = certificateSettings;
+        courseware.attributes['reminder-settings'] = reminderSettings;
+        courseware.attributes['reset-progress-settings'] = resetProgressSettings;
 
         return dispatch('courseware-instances/update', courseware, { root: true });
     },
diff --git a/templates/courseware/mails/certificate.php b/templates/courseware/mails/certificate.php
new file mode 100644
index 0000000000000000000000000000000000000000..ed1e099de03a4665c0bdb6c4abbee4a8bf4d0c75
--- /dev/null
+++ b/templates/courseware/mails/certificate.php
@@ -0,0 +1,22 @@
+<?php
+$p = '<p style="font-size: 20px; text-align: center;">';
+$span_bold = '<br /><br /><span style="font-size: 20px; text-align: center; font-weight: bold">';
+$span_close = '</span><br /><br />';
+switch($user->geschlecht) {
+    case 1:
+        $anrede = _('Herr');
+        break;
+    case 2:
+        $anrede = _('Frau');
+        break;
+    default:
+        $anrede= '';
+}
+echo $p;
+printf(
+    _("Hiermit wird bescheinigt, dass %s am %s erfolgreich am Seminar %s teilgenommen hat."),
+    $span_bold . $anrede . ' ' . $user->getFullname() . $span_close,
+    $span_bold . date('d.m.Y', time()) . $span_close,
+    $span_bold . $course->name . $span_close
+);
+echo '</p>';