diff --git a/app/workers/mails.php b/app/workers/mails.php index 1f7edf5db4..32fbcbcb66 100644 --- a/app/workers/mails.php +++ b/app/workers/mails.php @@ -1,45 +1,33 @@ desc('Audits worker') + ->inject('message') + ->inject('dbForProject') + ->inject('register') + ->callback(fn($message, $dbForProject, $register) => $this->action($message, $dbForProject, $register)); + } -/** - * Returns true if all the required terms in a locale exist. False otherwise - * - * @param $locale - * @param $prefix - * - * @return bool - */ -Server::setResource('doesLocaleExist', function () { - return function (Locale $locale, string $prefix) { + public function action(Message $message, $dbForProject, $register): void + { - if (!$locale->getText('emails.sender') || !$locale->getText("$prefix.hello") || !$locale->getText("$prefix.subject") || !$locale->getText("$prefix.body") || !$locale->getText("$prefix.footer") || !$locale->getText("$prefix.thanks") || !$locale->getText("$prefix.signature")) { - return false; - } - - return true; - }; -}); - -$server->job() - ->inject('message') - ->inject('doesLocaleExist') - ->inject('register') - ->action(function (Message $message, callable $doesLocaleExist, Registry $register) { $payload = $message->getPayload() ?? []; if (empty($payload)) { @@ -72,37 +60,37 @@ $server->job() $locale = new Locale($payload['locale']); $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); - if (!$doesLocaleExist($locale, $prefix)) { - $locale->setDefault('en'); - } + if (!$doesLocaleExist($locale, $prefix)) { + $locale->setDefault('en'); + } $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); $body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl'); $subject = ''; - switch ($type) { - case MAIL_TYPE_CERTIFICATE: - $domain = $payload['domain']; - $error = $payload['error']; - $attempt = $payload['attempt']; + switch ($type) { + case MAIL_TYPE_CERTIFICATE: + $domain = $payload['domain']; + $error = $payload['error']; + $attempt = $payload['attempt']; - $subject = \sprintf($locale->getText("$prefix.subject"), $domain); - $body->setParam('{{domain}}', $domain); - $body->setParam('{{error}}', $error); - $body->setParam('{{attempt}}', $attempt); - break; - case MAIL_TYPE_INVITATION: - $subject = \sprintf($locale->getText("$prefix.subject"), $team->getAttribute('name'), $projectName); - $body->setParam('{{owner}}', $user->getAttribute('name')); - $body->setParam('{{team}}', $team->getAttribute('name')); - break; - case MAIL_TYPE_RECOVERY: - case MAIL_TYPE_VERIFICATION: - case MAIL_TYPE_MAGIC_SESSION: - $subject = $locale->getText("$prefix.subject"); - break; - default: - throw new Exception('Undefined Mail Type : ' . $type, 500); - } + $subject = \sprintf($locale->getText("$prefix.subject"), $domain); + $body->setParam('{{domain}}', $domain); + $body->setParam('{{error}}', $error); + $body->setParam('{{attempt}}', $attempt); + break; + case MAIL_TYPE_INVITATION: + $subject = \sprintf($locale->getText("$prefix.subject"), $team->getAttribute('name'), $projectName); + $body->setParam('{{owner}}', $user->getAttribute('name')); + $body->setParam('{{team}}', $team->getAttribute('name')); + break; + case MAIL_TYPE_RECOVERY: + case MAIL_TYPE_VERIFICATION: + case MAIL_TYPE_MAGIC_SESSION: + $subject = $locale->getText("$prefix.subject"); + break; + default: + throw new Exception('Undefined Mail Type : ' . $type, 500); + } $body ->setParam('{{subject}}', $subject) @@ -147,12 +135,30 @@ $server->job() $mail->Body = $body; $mail->AltBody = \strip_tags($body); - try { - $mail->send(); - } catch (\Exception $error) { - throw new Exception('Error sending mail: ' . $error->getMessage(), 500); + try { + $mail->send(); + } catch (\Exception $error) { + throw new Exception('Error sending mail: ' . $error->getMessage(), 500); + } } - }); -$server->workerStart(); -$server->start(); + +/** + * Returns true if all the required terms in a locale exist. False otherwise + * + * @param Locale $locale + * @param string $prefix + * @return bool + */ +private function doesLocaleExist(Locale $locale, string $prefix) +{ + + if (!$locale->getText('emails.sender') || !$locale->getText("$prefix.hello") || !$locale->getText("$prefix.subject") || !$locale->getText("$prefix.body") || !$locale->getText("$prefix.footer") || !$locale->getText("$prefix.thanks") || !$locale->getText("$prefix.signature")) { + return false; + } + + return true; +} + + +} \ No newline at end of file diff --git a/bin/worker-mails b/bin/worker-mails index 87fa64cf7c..0e0918ee3e 100644 --- a/bin/worker-mails +++ b/bin/worker-mails @@ -1,10 +1,3 @@ #!/bin/sh -if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ] -then - REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}" -else - REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}" -fi - -INTERVAL=1 QUEUE='v1-mails' APP_INCLUDE='/usr/src/code/app/workers/mails.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php \ No newline at end of file +QUEUE=v1-mails php /usr/src/code/app/worker.php mails $@ \ No newline at end of file diff --git a/src/Appwrite/Platform/Services/Workers.php b/src/Appwrite/Platform/Services/Workers.php index 1ed65a135b..9db2b38b32 100644 --- a/src/Appwrite/Platform/Services/Workers.php +++ b/src/Appwrite/Platform/Services/Workers.php @@ -4,7 +4,8 @@ namespace Appwrite\Platform\Services; use Utopia\Platform\Service; use Appwrite\Platform\Workers\Audits; -use Appwrite\Platform\Workers\webhooks; +use Appwrite\Platform\Workers\Webhooks; +use Appwrite\Platform\Workers\Mails; class Workers extends Service { @@ -13,7 +14,8 @@ class Workers extends Service $this->type = self::TYPE_WORKER; $this ->addAction(Audits::getName(), new Audits()) - ->addAction(Webhooks::getName(), new webhooks()) + ->addAction(Webhooks::getName(), new Webhooks()) + ->addAction(Mails::getName(), new Mails()) ; } } diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php new file mode 100644 index 0000000000..8c9c20f519 --- /dev/null +++ b/src/Appwrite/Platform/Workers/Mails.php @@ -0,0 +1,166 @@ +desc('Mails worker') + ->inject('message') + ->inject('register') + ->callback(fn($message, $register) => $this->action($message, $register)); + } + + public function action(Message $message, $register): void + { + + $payload = $message->getPayload() ?? []; + + if (empty($payload)) { + throw new Exception('Missing payload'); + } + + if (empty(App::getEnv('_APP_SMTP_HOST'))) { + Console::info('Skipped mail processing. No SMTP server hostname has been set.'); + return; + } + + $project = new Document($payload['project'] ?? []); + $user = new Document($payload['user'] ?? []); + $team = new Document($payload['team'] ?? []); + + $recipient = $payload['recipient']; + $url = $payload['url']; + $name = $payload['name']; + $type = $payload['type']; + + $prefix = match ($type) { + MAIL_TYPE_RECOVERY => 'emails.recovery', + MAIL_TYPE_CERTIFICATE => 'emails.certificate', + MAIL_TYPE_INVITATION => 'emails.invitation', + MAIL_TYPE_VERIFICATION => 'emails.verification', + MAIL_TYPE_MAGIC_SESSION => 'emails.magicSession', + default => throw new Exception('Undefined Mail Type : ' . $type, 500) + }; + + $locale = new Locale($payload['locale']); + $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); + + if (!$this->doesLocaleExist($locale, $prefix)) { + $locale->setDefault('en'); + } + + $from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName); + $body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl'); + $subject = ''; + switch ($type) { + case MAIL_TYPE_CERTIFICATE: + $domain = $payload['domain']; + $error = $payload['error']; + $attempt = $payload['attempt']; + + $subject = \sprintf($locale->getText("$prefix.subject"), $domain); + $body->setParam('{{domain}}', $domain); + $body->setParam('{{error}}', $error); + $body->setParam('{{attempt}}', $attempt); + break; + case MAIL_TYPE_INVITATION: + $subject = \sprintf($locale->getText("$prefix.subject"), $team->getAttribute('name'), $projectName); + $body->setParam('{{owner}}', $user->getAttribute('name')); + $body->setParam('{{team}}', $team->getAttribute('name')); + break; + case MAIL_TYPE_RECOVERY: + case MAIL_TYPE_VERIFICATION: + case MAIL_TYPE_MAGIC_SESSION: + $subject = $locale->getText("$prefix.subject"); + break; + default: + throw new Exception('Undefined Mail Type : ' . $type, 500); + } + + $body + ->setParam('{{subject}}', $subject) + ->setParam('{{hello}}', $locale->getText("$prefix.hello")) + ->setParam('{{name}}', $name) + ->setParam('{{body}}', $locale->getText("$prefix.body")) + ->setParam('{{redirect}}', $url) + ->setParam('{{footer}}', $locale->getText("$prefix.footer")) + ->setParam('{{thanks}}', $locale->getText("$prefix.thanks")) + ->setParam('{{signature}}', $locale->getText("$prefix.signature")) + ->setParam('{{project}}', $projectName) + ->setParam('{{direction}}', $locale->getText('settings.direction')) + ->setParam('{{bg-body}}', '#f7f7f7') + ->setParam('{{bg-content}}', '#ffffff') + ->setParam('{{text-content}}', '#000000'); + + $body = $body->render(); + + /** @var PHPMailer $mail */ + $mail = $register->get('smtp'); + + // Set project mail + /*$register->get('smtp') + ->setFrom( + App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), + ($project->getId() === 'console') + ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) + : \sprintf(Locale::getText('account.emails.team'), $project->getAttribute('name') + ) + );*/ + + $mail->clearAddresses(); + $mail->clearAllRecipients(); + $mail->clearReplyTos(); + $mail->clearAttachments(); + $mail->clearBCCs(); + $mail->clearCCs(); + + $mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from)); + $mail->addAddress($recipient, $name); + $mail->Subject = $subject; + $mail->Body = $body; + $mail->AltBody = \strip_tags($body); + + try { + $mail->send(); + } catch (\Exception $error) { + throw new Exception('Error sending mail: ' . $error->getMessage(), 500); + } + } + + + /** + * Returns true if all the required terms in a locale exist. False otherwise + * + * @param Locale $locale + * @param string $prefix + * @return bool + * @throws Exception + */ + private function doesLocaleExist(Locale $locale, string $prefix): bool + { + + if (!$locale->getText('emails.sender') || !$locale->getText("$prefix.hello") || !$locale->getText("$prefix.subject") || !$locale->getText("$prefix.body") || !$locale->getText("$prefix.footer") || !$locale->getText("$prefix.thanks") || !$locale->getText("$prefix.signature")) { + return false; + } + + return true; + } +}