From 70a3820009a97396bf582f33e5a89972ce0bb237 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 4 Oct 2023 15:08:32 -0700 Subject: [PATCH 1/5] Remove unused mail vars --- app/controllers/api/account.php | 9 --------- app/controllers/api/teams.php | 3 --- src/Appwrite/Platform/Workers/Certificates.php | 5 +---- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 2bc7759620..b6a47efea1 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1057,9 +1057,6 @@ App::post('/v1/account/sessions/magic-url') 'thanks' => $locale->getText("emails.magicSession.thanks"), 'signature' => $locale->getText("emails.magicSession.signature"), 'direction' => $locale->getText('settings.direction'), - 'bg-body' => '#f7f7f7', - 'bg-content' => '#ffffff', - 'text-content' => '#000000', /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => '', 'team' => '', @@ -2514,9 +2511,6 @@ App::post('/v1/account/recovery') 'thanks' => $locale->getText("emails.recovery.thanks"), 'signature' => $locale->getText("emails.recovery.signature"), 'direction' => $locale->getText('settings.direction'), - 'bg-body' => '#f7f7f7', - 'bg-content' => '#ffffff', - 'text-content' => '#000000', /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => $profile->getAttribute('name'), 'team' => '', @@ -2766,9 +2760,6 @@ App::post('/v1/account/verification') 'thanks' => $locale->getText("emails.verification.thanks"), 'signature' => $locale->getText("emails.verification.signature"), 'direction' => $locale->getText('settings.direction'), - 'bg-body' => '#f7f7f7', - 'bg-content' => '#ffffff', - 'text-content' => '#000000', /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => $user->getAttribute('name'), 'team' => '', diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 0a887908bb..a089a8f37c 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -613,9 +613,6 @@ App::post('/v1/teams/:teamId/memberships') 'thanks' => $locale->getText("emails.invitation.thanks"), 'signature' => $locale->getText("emails.invitation.signature"), 'direction' => $locale->getText('settings.direction'), - 'bg-body' => '#f7f7f7', - 'bg-content' => '#ffffff', - 'text-content' => '#000000', /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => $user->getAttribute('name'), 'team' => $team->getAttribute('name'), diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 02c1835dd5..31f9caa292 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -441,10 +441,7 @@ class Certificates extends Action ->setParam('{{thanks}}', $locale->getText("emails.certificate.thanks")) ->setParam('{{signature}}', $locale->getText("emails.certificate.signature")) ->setParam('{{project}}', 'Console') - ->setParam('{{direction}}', $locale->getText('settings.direction')) - ->setParam('{{bg-body}}', '#f7f7f7') - ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{text-content}}', '#000000'); + ->setParam('{{direction}}', $locale->getText('settings.direction')); $queueForMails ->setRecipient(App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS')) From 3206cee36fa184d6520422750c5273ae355f938f Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 4 Oct 2023 16:05:50 -0700 Subject: [PATCH 2/5] Leave user placeholder in default email template This matches up with the default template and gives the developer an idea about the available variables and how to use them. --- app/controllers/api/projects.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index fe7759a6df..3c1b9417f5 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1718,7 +1718,6 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale') $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); $message ->setParam('{{hello}}', $localeObj->getText("emails.{$type}.hello")) - ->setParam('{{user}}', '') ->setParam('{{footer}}', $localeObj->getText("emails.{$type}.footer")) ->setParam('{{body}}', $localeObj->getText('emails.' . $type . '.body')) ->setParam('{{thanks}}', $localeObj->getText("emails.{$type}.thanks")) From 836ce852ed144711f27deae93d2aa19bbf547d82 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 4 Oct 2023 16:14:27 -0700 Subject: [PATCH 3/5] Refactor email templates Update the mails worker to only be responsible for building the final email using the base (layout) template and the user, team, project, and redirect variables. It is the responsibility of the controller to perform localization and determine whether a custom or default email template should be used. If the default one is used, it has to be rendered using the hello, footer, thanks, and signature variables so that it matches the custom template. Then, it can be sent to the worker. --- app/controllers/api/account.php | 40 +++++++++++-------------- app/controllers/api/teams.php | 13 ++++---- src/Appwrite/Platform/Workers/Mails.php | 9 ++++-- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index b6a47efea1..0a067cc8fd 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1000,7 +1000,12 @@ App::post('/v1/account/sessions/magic-url') $customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? []; $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); - $message->setParam('{{body}}', $body); + $message + ->setParam('{{body}}', $body) + ->setParam('{{hello}}', $locale->getText("emails.magicSession.hello")) + ->setParam('{{footer}}', $locale->getText("emails.magicSession.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.magicSession.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.magicSession.signature")); $body = $message->render(); $smtp = $project->getAttribute('smtp', []); @@ -1050,12 +1055,6 @@ App::post('/v1/account/sessions/magic-url') } $emailVariables = [ - 'subject' => $subject, - 'hello' => $locale->getText("emails.magicSession.hello"), - 'body' => $body, - 'footer' => $locale->getText("emails.magicSession.footer"), - 'thanks' => $locale->getText("emails.magicSession.thanks"), - 'signature' => $locale->getText("emails.magicSession.signature"), 'direction' => $locale->getText('settings.direction'), /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => '', @@ -2454,7 +2453,12 @@ App::post('/v1/account/recovery') $customTemplate = $project->getAttribute('templates', [])['email.recovery-' . $locale->default] ?? []; $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); - $message->setParam('{{body}}', $body); + $message + ->setParam('{{body}}', $body) + ->setParam('{{hello}}', $locale->getText("emails.recovery.hello")) + ->setParam('{{footer}}', $locale->getText("emails.recovery.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.recovery.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.recovery.signature")); $body = $message->render(); $smtp = $project->getAttribute('smtp', []); @@ -2504,12 +2508,6 @@ App::post('/v1/account/recovery') } $emailVariables = [ - 'subject' => $subject, - 'hello' => $locale->getText("emails.recovery.hello"), - 'body' => $body, - 'footer' => $locale->getText("emails.recovery.footer"), - 'thanks' => $locale->getText("emails.recovery.thanks"), - 'signature' => $locale->getText("emails.recovery.signature"), 'direction' => $locale->getText('settings.direction'), /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => $profile->getAttribute('name'), @@ -2518,7 +2516,6 @@ App::post('/v1/account/recovery') 'redirect' => $url ]; - $queueForMails ->setRecipient($profile->getAttribute('email', '')) ->setName($profile->getAttribute('name')) @@ -2703,7 +2700,12 @@ App::post('/v1/account/verification') $customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? []; $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); - $message->setParam('{{body}}', $body); + $message + ->setParam('{{body}}', $body) + ->setParam('{{hello}}', $locale->getText("emails.verification.hello")) + ->setParam('{{footer}}', $locale->getText("emails.verification.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.verification.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.verification.signature")); $body = $message->render(); $smtp = $project->getAttribute('smtp', []); @@ -2753,12 +2755,6 @@ App::post('/v1/account/verification') } $emailVariables = [ - 'subject' => $subject, - 'hello' => $locale->getText("emails.verification.hello"), - 'body' => $body, - 'footer' => $locale->getText("emails.verification.footer"), - 'thanks' => $locale->getText("emails.verification.thanks"), - 'signature' => $locale->getText("emails.verification.signature"), 'direction' => $locale->getText('settings.direction'), /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => $user->getAttribute('name'), diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index a089a8f37c..2ee351f469 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -555,7 +555,12 @@ App::post('/v1/teams/:teamId/memberships') $customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? []; $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); - $message->setParam('{{body}}', $body); + $message + ->setParam('{{body}}', $body) + ->setParam('{{hello}}', $locale->getText("emails.invitation.hello")) + ->setParam('{{footer}}', $locale->getText("emails.invitation.footer")) + ->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks")) + ->setParam('{{signature}}', $locale->getText("emails.invitation.signature")); $body = $message->render(); $smtp = $project->getAttribute('smtp', []); @@ -606,12 +611,6 @@ App::post('/v1/teams/:teamId/memberships') $emailVariables = [ 'owner' => $user->getAttribute('name'), - 'subject' => $subject, - 'hello' => $locale->getText("emails.invitation.hello"), - 'body' => $body, - 'footer' => $locale->getText("emails.invitation.footer"), - 'thanks' => $locale->getText("emails.invitation.thanks"), - 'signature' => $locale->getText("emails.invitation.signature"), 'direction' => $locale->getText('settings.direction'), /* {{user}} ,{{team}}, {{project}} and {{redirect}} are required in the templates */ 'user' => $user->getAttribute('name'), diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php index 7a20212c9c..a29f2c6886 100644 --- a/src/Appwrite/Platform/Workers/Mails.php +++ b/src/Appwrite/Platform/Workers/Mails.php @@ -58,13 +58,16 @@ class Mails extends Action $subject = $payload['subject']; $variables = $payload['variables']; $name = $payload['name']; - $body = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-base.tpl'); + $body = $payload['body']; + + $bodyTemplate = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-base.tpl'); + $bodyTemplate->setParam('{{body}}', $body); foreach ($variables as $key => $value) { - $body->setParam('{{' . $key . '}}', $value); + $bodyTemplate->setParam('{{' . $key . '}}', $value); } - $body = $body->render(); + $body = $bodyTemplate->render(); /** @var PHPMailer $mail */ $mail = empty($smtp) From fc4fa977a01c1339f20a513d91ea8451be1c3a05 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 4 Oct 2023 16:34:38 -0700 Subject: [PATCH 4/5] Update emails from certificate worker to match pattern of other emails Since the certificate worker is sending a job to the mails worker just like the controllers, it should prepare the email in the same way by localizing and then sending the inner template for the mail worker to apply the layout and final variables. This commit also fixes a problem with a missing subject. --- .../Platform/Workers/Certificates.php | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 31f9caa292..ade2125e4a 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -426,26 +426,31 @@ class Certificates extends Action $locale->setDefault('en'); } - $body = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-base.tpl'); - $subject = \sprintf($locale->getText("emails.certificate.subject"), $domain); - $body - ->setParam('{{domain}}', $domain) - ->setParam('{{error}}', $errorMessage) - ->setParam('{{attempt}}', $attempt) - ->setParam('{{subject}}', $subject) - ->setParam('{{hello}}', $locale->getText("emails.certificate.hello")) + + $message = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-inner-base.tpl'); + $message ->setParam('{{body}}', $locale->getText("emails.certificate.body")) - ->setParam('{{redirect}}', 'https://' . $domain) + ->setParam('{{hello}}', $locale->getText("emails.certificate.hello")) ->setParam('{{footer}}', $locale->getText("emails.certificate.footer")) ->setParam('{{thanks}}', $locale->getText("emails.certificate.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.certificate.signature")) - ->setParam('{{project}}', 'Console') - ->setParam('{{direction}}', $locale->getText('settings.direction')); + ->setParam('{{signature}}', $locale->getText("emails.certificate.signature")); + $body = $message->render(); + + $emailVariables = [ + 'direction' => $locale->getText('settings.direction'), + 'domain' => $domain, + 'error' => '
' . $errorMessage . '
', + 'attempt' => $attempt, + 'project' => 'Console', + 'redirect' => 'https://' . $domain, + ]; $queueForMails ->setRecipient(App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS')) - ->setBody($body->render()) + ->setSubject($subject) + ->setBody($body) + ->setVariables($emailVariables) ->setName('Appwrite Administrator') ->trigger(); } From 7c1ab91ebce8ce9d7dfd070156375369dbe42567 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 4 Oct 2023 16:53:38 -0700 Subject: [PATCH 5/5] Add support for variables in email template subject --- src/Appwrite/Platform/Workers/Mails.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php index a29f2c6886..94a2a46087 100644 --- a/src/Appwrite/Platform/Workers/Mails.php +++ b/src/Appwrite/Platform/Workers/Mails.php @@ -62,13 +62,18 @@ class Mails extends Action $bodyTemplate = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-base.tpl'); $bodyTemplate->setParam('{{body}}', $body); - foreach ($variables as $key => $value) { $bodyTemplate->setParam('{{' . $key . '}}', $value); } - $body = $bodyTemplate->render(); + $subjectTemplate = Template::fromString($subject); + foreach ($variables as $key => $value) { + $subjectTemplate->setParam('{{' . $key . '}}', $value); + } + // render() will return the subject in

tags, so use strip_tags() to remove them + $subject = \strip_tags($subjectTemplate->render()); + /** @var PHPMailer $mail */ $mail = empty($smtp) ? $register->get('smtp')