Update the email log entry when delivery succeeds or fails
authorTim Düsterhus <duesterhus@woltlab.com>
Mon, 15 Feb 2021 11:09:16 +0000 (12:09 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Thu, 18 Feb 2021 15:24:45 +0000 (16:24 +0100)
wcfsetup/install/files/lib/system/background/job/EmailDeliveryBackgroundJob.class.php
wcfsetup/install/files/lib/system/email/transport/IStatusReportingEmailTransport.class.php [new file with mode: 0644]

index 1194682e4137952eb9a1816be8c009b6275ef9fc..2930599c80dfe0a7240ba84bf415755c08c43ee4 100644 (file)
@@ -7,6 +7,7 @@ use wcf\data\email\log\entry\EmailLogEntryAction;
 use wcf\system\email\Email;
 use wcf\system\email\Mailbox;
 use wcf\system\email\transport\exception\PermanentFailure;
+use wcf\system\email\transport\IStatusReportingEmailTransport;
 use wcf\system\email\UserMailbox;
 
 /**
@@ -48,6 +49,11 @@ class EmailDeliveryBackgroundJob extends AbstractBackgroundJob
      */
     protected $emailLogEntryId;
 
+    /**
+     * @var string
+     */
+    private $lastErrorMessage = '';
+
     /**
      * instance of the default transport
      * @var \wcf\system\email\transport\IEmailTransport
@@ -83,10 +89,39 @@ class EmailDeliveryBackgroundJob extends AbstractBackgroundJob
                 'recipient' => $this->envelopeTo->getAddress(),
                 'recipientID' => ($this->envelopeTo instanceof UserMailbox) ? $this->envelopeTo->getUser()->userID : null,
                 'status' => EmailLogEntry::STATUS_NEW,
-            ]
+            ],
         ]))->executeAction()['returnValues'];
     }
 
+    /**
+     * Updates the status of the log entry.
+     */
+    final private function updateStatus(string $status, string $message = ''): void
+    {
+        (new EmailLogEntryAction([$this->emailLogEntryId], 'update', [
+            'data' => [
+                'status' => $status,
+                'message' => $message,
+            ],
+        ]))->executeAction();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function onFailure()
+    {
+        $this->updateStatus(EmailLogEntry::STATUS_TRANSIENT_FAILURE, $this->lastErrorMessage);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function onFinalFailure()
+    {
+        $this->updateStatus(EmailLogEntry::STATUS_PERMANENT_FAILURE, $this->lastErrorMessage);
+    }
+
     /**
      * Emails will be sent with an increasing timeout between the tries.
      *
@@ -141,11 +176,35 @@ class EmailDeliveryBackgroundJob extends AbstractBackgroundJob
         }
 
         try {
-            self::$transport->deliver($this->email, $this->envelopeFrom, $this->envelopeTo);
+            try {
+                $return = self::$transport->deliver($this->email, $this->envelopeFrom, $this->envelopeTo);
+                if (self::$transport instanceof IStatusReportingEmailTransport) {
+                    $successMessage = $return;
+                } else {
+                    $successMessage = '';
+                }
+            } catch (\Throwable $e) {
+                // This is a hack, because we can't add additional optional parameters to on(Final)?Failure
+                // in AbstractBackgroundJob for compatibility reasons.
+
+                $this->lastErrorMessage = $e->getMessage();
+                throw $e;
+            }
         } catch (PermanentFailure $e) {
             // no need for retrying. Eat Exception and log the error.
             \wcf\functions\exception\logThrowable($e);
             $this->onFinalFailure();
+
+            return;
+        }
+
+        // At this point the email delivery succeeded.
+
+        try {
+            $this->updateStatus(EmailLogEntry::STATUS_SUCCESS, $successMessage);
+        } catch (\Throwable $e) {
+            // Ignore all errors, otherwise we might deliver the email multiple times.
+            \wcf\functions\exception\logThrowable($e);
         }
     }
 }
diff --git a/wcfsetup/install/files/lib/system/email/transport/IStatusReportingEmailTransport.class.php b/wcfsetup/install/files/lib/system/email/transport/IStatusReportingEmailTransport.class.php
new file mode 100644 (file)
index 0000000..a7b9a6d
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+namespace wcf\system\email\transport;
+
+use wcf\system\email\Email;
+use wcf\system\email\Mailbox;
+
+/**
+ * An IStatusReportingEmailTransport returns a status message from deliver().
+ *
+ * @author  Tim Duesterhus
+ * @copyright   2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Email\Transport
+ * @since   5.4
+ */
+interface IStatusReportingEmailTransport extends IEmailTransport
+{
+    /**
+     * @inheritDoc
+     */
+    public function deliver(Email $email, Mailbox $envelopeFrom, Mailbox $envelopeTo): string;
+}