From cbe9a7fb37390ec9b098f65027111f3d0d1ce007 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 15 Jun 2015 21:11:04 +0200 Subject: [PATCH] Add EmailDeliveryBackgroundJob and DebugEmailTransport --- .../job/EmailDeliveryBackgroundJob.class.php | 74 +++++++++++++++++++ .../files/lib/system/email/Email.class.php | 36 ++++++++- .../email/mime/AttachmentMimePart.class.php | 9 ++- .../transport/DebugEmailTransport.class.php | 49 ++++++++++++ .../email/transport/EmailTransport.class.php | 24 ++++++ 5 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/background/job/EmailDeliveryBackgroundJob.class.php create mode 100644 wcfsetup/install/files/lib/system/email/transport/DebugEmailTransport.class.php create mode 100644 wcfsetup/install/files/lib/system/email/transport/EmailTransport.class.php diff --git a/wcfsetup/install/files/lib/system/background/job/EmailDeliveryBackgroundJob.class.php b/wcfsetup/install/files/lib/system/background/job/EmailDeliveryBackgroundJob.class.php new file mode 100644 index 0000000000..93d52a9c6d --- /dev/null +++ b/wcfsetup/install/files/lib/system/background/job/EmailDeliveryBackgroundJob.class.php @@ -0,0 +1,74 @@ + + * @package com.woltlab.wcf + * @subpackage system.background.job + * @category Community Framework + */ +class EmailDeliveryBackgroundJob extends AbstractBackgroundJob { + /** + * email to send + * @var \wcf\system\email\Email + */ + protected $email; + + /** + * recipient mailbox + * @var \wcf\system\email\Mailbox + */ + protected $mailbox; + + /** + * instance of the default transport + * @var \wcf\system\email\transport\EmailTransport + */ + protected static $transport = null; + + /** + * Creates the job using the given the email and the destination mailbox. + * + * @param \wcf\system\email\Email $email + * @param \wcf\system\email\Mailbox $mailbox + * @see \wcf\system\email\transport\EmailTransport + */ + public function __construct(Email $email, Mailbox $mailbox) { + $this->email = $email; + $this->mailbox = $mailbox; + } + + /** + * Emails will be sent with an increasing timeout between the tries. + * + * @return int 5 minutes, 30 minutes, 2 hours. + */ + public function retryAfter() { + switch ($this->getFailures()) { + case 1: + return 5 * 60; + case 2: + return 30 * 60; + case 3: + return 2 * 60 * 60; + } + } + + /** + * @see \wcf\system\background\job\AbstractJob::perform(); + */ + public function perform() { + if (self::$transport === null) { + $name = '\wcf\system\email\transport\\'.ucfirst(MAIL_SEND_METHOD).'EmailTransport'; + self::$transport = new $name(); + } + + self::$transport->deliver($this->email, $this->mailbox); + } +} diff --git a/wcfsetup/install/files/lib/system/email/Email.class.php b/wcfsetup/install/files/lib/system/email/Email.class.php index b79e440816..bd1cd0f818 100644 --- a/wcfsetup/install/files/lib/system/email/Email.class.php +++ b/wcfsetup/install/files/lib/system/email/Email.class.php @@ -1,7 +1,9 @@ extraHeaders[] = [ $header, EmailGrammar::encodeMimeHeader($value) ]; + $this->extraHeaders[] = [ $header, EmailGrammar::encodeQuotedPrintableHeader($value) ]; } /** @@ -559,9 +561,41 @@ class Email { $body .= $text; } + // TODO: Where to put the email signature? + return $body; } + /** + * Returns needed AbstractBackgroundJobs to deliver this email to every recipient. + * + * @return array<\wcf\system\background\job\AbstractBackgroundJob> + */ + public function getJobs() { + $jobs = [ ]; + + // ensure every header is filled in + $this->getHeaders(); + + foreach ($this->recipients as $recipient) { + $mail = clone $this; + + if ($recipient[1] instanceof UserMailbox) { + $mail->addHeader('X-Community-Framework-Recipient', $recipient[1]->getUser()->username); + } + + $data = [ 'mail' => $mail, 'recipient' => $recipient, 'skip' => false ]; + EventHandler::getInstance()->fireAction($this, 'getJobs', $data); + + // an event decided that this email should be skipped + if ($data['skip']) continue; + + $jobs[] = new EmailDeliveryBackgroundJob($mail, $recipient[1]); + } + + return $jobs; + } + /** * Returns the email RFC 2822 representation of this email. * diff --git a/wcfsetup/install/files/lib/system/email/mime/AttachmentMimePart.class.php b/wcfsetup/install/files/lib/system/email/mime/AttachmentMimePart.class.php index ee1a16903d..b1dcc69e88 100644 --- a/wcfsetup/install/files/lib/system/email/mime/AttachmentMimePart.class.php +++ b/wcfsetup/install/files/lib/system/email/mime/AttachmentMimePart.class.php @@ -32,6 +32,12 @@ class AttachmentMimePart extends AbstractMimePart { */ protected $mimeType; + /** + * the file contents + * @var string + */ + protected $content = ''; + /** * Creates a new Attachment. * @@ -47,6 +53,7 @@ class AttachmentMimePart extends AbstractMimePart { $this->mimeType = $mimeType ?: (FileUtil::getMimeType($path) ?: 'application/octet-stream'); $this->path = $path; $this->filename = $filename ?: basename($path); + $this->content = file_get_contents($this->path); } /** @@ -78,6 +85,6 @@ class AttachmentMimePart extends AbstractMimePart { * @see \wcf\system\email\mime\AbstractMimePart::getContent() */ public function getContent() { - return file_get_contents($this->path); + return $this->content; } } diff --git a/wcfsetup/install/files/lib/system/email/transport/DebugEmailTransport.class.php b/wcfsetup/install/files/lib/system/email/transport/DebugEmailTransport.class.php new file mode 100644 index 0000000000..5ef9660879 --- /dev/null +++ b/wcfsetup/install/files/lib/system/email/transport/DebugEmailTransport.class.php @@ -0,0 +1,49 @@ + + * @package com.woltlab.wcf + * @subpackage system.email.transport + * @category Community Framework + */ +class DebugEmailTransport implements EmailTransport { + /** + * mbox file + * @var \wcf\system\io\File + */ + protected $mbox = null; + + /** + * Creates a new DebugTransport using the given mbox as target. + * + * @param string $mbox mbox location or null for default location + */ + public function __construct($mbox = null) { + if ($mbox === null) $mbox = WCF_DIR.'log/debug.mbox'; + + $this->mbox = new File($mbox, 'ab'); + } + + /** + * Writes the given $email into the mbox. + * + * @param \wcf\system\email\Email $email + * @param \wcf\system\email\Mailbox $envelopeTo + */ + public function deliver(Email $email, Mailbox $envelopeTo) { + $this->mbox->write("From ".$email->getSender()->getAddress()." ".DateUtil::getDateTimeByTimestamp(TIME_NOW)->format('D M d H:i:s Y')."\r\n"); + $this->mbox->write("Delivered-To: ".$envelopeTo->getAddress()."\r\n"); + $this->mbox->write($email); + $this->mbox->write("\r\n"); + } +} diff --git a/wcfsetup/install/files/lib/system/email/transport/EmailTransport.class.php b/wcfsetup/install/files/lib/system/email/transport/EmailTransport.class.php new file mode 100644 index 0000000000..b19b70a9d5 --- /dev/null +++ b/wcfsetup/install/files/lib/system/email/transport/EmailTransport.class.php @@ -0,0 +1,24 @@ + + * @package com.woltlab.wcf + * @subpackage system.email.transport + * @category Community Framework + */ +interface EmailTransport { + /** + * Delivers the given $email to the given Mailbox as the recipient. + * + * @param \wcf\system\email\Email $email + * @param \wcf\system\email\Mailbox $envelopeTo + */ + public function deliver(Email $email, Mailbox $envelopeTo); +} -- 2.20.1