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;
/**
*/
protected $emailLogEntryId;
+ /**
+ * @var string
+ */
+ private $lastErrorMessage = '';
+
/**
* instance of the default transport
* @var \wcf\system\email\transport\IEmailTransport
'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.
*
}
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);
}
}
}
--- /dev/null
+<?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;
+}