Design your own email templates directly from the Strapi admin panel and use the magic to send programmatically email from your controllers / services.
Design your own email templates directly from the Strapi admin panel and use the magic to send programmatically email from your controllers / services.
Special thanks to:
If you can 😊
This plugin is compatible with Strapi v5.
How plugins are structured in v5 is way different than v4, so I am not trying to make this plugin compatible with v4. Use the Email Designer plugin here for v4.
npx create-strapi-app@latest my-project
)Install the plugin by runnig the following command:
npm install strapi-plugin-email-designer-v5
By default, Strapi's security is tight. You will need to add the following to your config/middleware.ts
file:
1{
2 name: "strapi::security",
3 config: {
4 contentSecurityPolicy: {
5 useDefaults: true,
6 directives: {
7 "script-src": ["'self'", "'unsafe-inline'", "editor.unlayer.com"],
8 "frame-src": ["'self'", "editor.unlayer.com"],
9 upgradeInsecureRequests: null,
10 },
11 },
12 },
13}
Ensure that you replace the "strapi::security"
line in the file with the above.
The plugin configuration accepts most of the properties that can be passed to the Unlayer editor. You can get more information about them here: https://docs.unlayer.com/docs/getting-started#configuration-options
This is the type definition for the configuration:
1import type { EmailEditorProps } from "react-email-editor";
2
3export type EmailConfig = Pick<
4 NonNullable<EmailEditorProps["options"]>,
5 | "projectId"
6 | "locale"
7 | "appearance"
8 | "user"
9 | "mergeTags"
10 | "designTags"
11 | "specialLinks"
12 | "tools"
13 | "blocks"
14 | "fonts"
15 | "safeHtml"
16 | "customCSS"
17 | "customJS"
18 | "textDirection"
19>;
If you are going to send emails from the Strapi backend, you need to configure the email plugin. You can visit the docs here to learn more
npm install @strapi/provider-email-nodemailer --save
Some options are passed by default to the editor. Expand the following object to see the default configuration:
1{
2 mergeTagsConfig: {
3 autocompleteTriggerChar: "@",
4 sort: false,
5 delimiter: ["{{", "}}"],
6 },
7 appearance: {
8 theme: "modern_light",
9 },
10 fonts: {
11 showDefaultFonts: false,
12 },
13 tools: {
14 image: {
15 properties: {
16 src: {
17 value: {
18 url: "https://picsum.photos/600/350",
19 },
20 },
21 },
22 },
23 },
24 mergeTags: {
25 core: {
26 name: "Core",
27 mergeTags: {
28 // Values that can be used in the Reset Password context
29 resetPassword: {
30 name: "Reset Password",
31 mergeTags: {
32 // User in the Reset Password context
33 user: {
34 name: "USER",
35 mergeTags: {
36 username: {
37 name: "Username",
38 value: "{{= USER.username }}",
39 sample: "john_doe",
40 },
41 email: {
42 name: "Email",
43 value: "{{= USER.email }}",
44 sample: "johndoe@example.com",
45 },
46 },
47 },
48 token: {
49 name: "TOKEN",
50 value: "{{= TOKEN }}",
51 sample: "corresponds-to-the-token-generated-to-be-able-to-reset-the-password",
52 },
53 url: {
54 name: "URL",
55 value: "{{= URL }}",
56 sample: "is-the-link-where-the-user-will-be-redirected-after-clicking-on-it-in-the-email",
57 },
58 serverUrl: {
59 name: "SERVER_URL",
60 value: "{{= SERVER_URL }}",
61 sample: "is-the-absolute-server-url-(configured-in-server-configuration)",
62 },
63 },
64 },
65 // Values that can be used in the Email Addres Confirmation context
66 addressConfirmation: {
67 name: "Confirm Address",
68 mergeTags: {
69 // User in the Email Address Confirmation context
70 user: {
71 name: "USER",
72 mergeTags: {
73 username: {
74 name: "Username",
75 value: "{{= USER.username }}",
76 sample: "john_doe",
77 },
78 email: {
79 name: "Email",
80 value: "{{= USER.email }}",
81 sample: "johndoe@example.com",
82 },
83 },
84 },
85 code: {
86 name: "CODE",
87 value: "{{= CODE }}",
88 sample: "corresponds-to-the-CODE-generated-to-be-able-confirm-the-user-email",
89 },
90 url: {
91 name: "URL",
92 value: "{{= URL }}",
93 sample:
94 "is-the-Strapi-backend-URL-that-confirms-the-code-(by-default-/auth/email-confirmation)",
95 },
96 serverUrl: {
97 name: "SERVER_URL",
98 value: "{{= SERVER_URL }}",
99 sample: "is-the-absolute-server-url-(configured-in-server-configuration)",
100 },
101 },
102 },
103 },
104 },
105 mustache: {
106 name: "Mustache",
107 mergeTags: {
108 basic: {
109 name: "Basic Output",
110 mergeTags: {
111 raw: {
112 name: "Display Raw Content",
113 value: "{{{REPLACE_ME}}}",
114 },
115 output: {
116 name: "Regular Output",
117 value: "{{REPLACE_ME}}",
118 },
119 dottedOutput: {
120 name: "Dot notation for Output",
121 value: "{{REPLACE_ME.NESTED_VALUE}}",
122 },
123 },
124 },
125 loops: {
126 name: "Loops",
127 mergeTags: {
128 raw: {
129 name: "Display Raw Content in Loop",
130 value: "{{#ARRAY_OR_OBJECT_TO_ITERATE}}\n{{{REPLACE_ME}}}\n{{/ARRAY_OR_OBJECT_TO_ITERATE}}",
131 },
132 output: {
133 name: "Regular Output in Loop",
134 value: "{{#ARRAY_OR_OBJECT_TO_ITERATE}}\n{{REPLACE_ME}}\n{{/ARRAY_OR_OBJECT_TO_ITERATE}}",
135 },
136 dottedOutput: {
137 name: "Dot notation for Output in Loop",
138 value:
139 "{{#ARRAY_OR_OBJECT_TO_ITERATE}}\n{{REPLACE_ME.NESTED_VALUE}}\n{{/ARRAY_OR_OBJECT_TO_ITERATE}}",
140 },
141 },
142 },
143 },
144 },
145 },
146}
If you wish to pass in any configuration, you can do so in the config/plugins.ts
file. Here is an example of how to pass in a custom configuration:
1// You can import the EmailConfig type from the plugin
2import type { EmailConfig } from "strapi-plugin-email-designer-5/dist/server/src";
3
4export default ({ env }) => ({
5 // You need Email configured if you are gonna send emails from the Strapi backend
6 // This is a simple configuration for development using MailDev
7 email: {
8 config: {
9 provider: "nodemailer",
10 providerOptions: {
11 host: "0.0.0.0",
12 port: 1025,
13 ignoreTLS: true,
14 },
15 },
16 },
17 // This is the configuration for the Email Designer plugin
18 "email-designer-5": {
19 enabled: true,
20 // Your custom configuration here
21 config: {
22 // Here the Merge Tags defined will be merged with the defaults above
23 mergeTags: {
24 company: {
25 name: "Company",
26 mergeTags: {
27 name: {
28 name: "Company Name",
29 value: "ACME Corp",
30 sample: "ACME Corp",
31 },
32 },
33 },
34 },
35 } as EmailConfig,
36 },
37});
After installing & configuring your app for the plugin, you can access the email designer by navigating to the Email Designer (v5)
section in the admin panel.
Click on the Create a new email
button to start a new design.
You can import a set of designs that were exported by the platform by clicking on the Import Email Templates
button located at the bottom right of the page.
You can export all your designs by clicking the Export Email Templates
button located at the bottom right of the page.
When you start a new design, a button will be located in the top right called Import
that allows you to import a single design. If the json file is valid Unlayer exported design, it will be imported into the editor.
Once you are done editing your design, you can click on the Save
button located at the top right of the page. The Template Reference ID
, Template Name
, & Subject
fields are required to save the design.(Well not the last two lol)
The Template Reference ID
is a unique identifier for the design. It is used to reference the design when sending emails programmatically.
The backend uses Mustache to render the templates. You can visit the Mustache documentation to learn more about how to use it.
You can send emails programmatically by using the email-designer-5
plugin. Here is an example of how to send an email:
!IMPORTANT
This is tested theindex.ts
file of thesrc
folder of my strapi project.
1// import type { Core } from '@strapi/strapi';
2
3export default {
4 /**
5 * An asynchronous register function that runs before
6 * your application is initialized.
7 *
8 * This gives you an opportunity to extend code.
9 */
10 register(/* { strapi }: { strapi: Core.Strapi } */) {},
11
12 /**
13 * An asynchronous bootstrap function that runs before
14 * your application gets started.
15 *
16 * This gives you an opportunity to set up your data model,
17 * run jobs, or perform some special logic.
18 */
19 async bootstrap(/* { strapi }: { strapi: Core.Strapi } */) {
20 try {
21 await strapi
22 .plugin("email-designer-5")
23 .service("email")
24 .sendTemplatedEmail(
25 {
26 // required
27 // This can also be an array of email addresses
28 to: "to@example.com",
29 // Optional
30 cc: ["zez@jakce.ad", "ilez@gevcanuso.la"],
31 // Optional
32 bcc: ["fud@darfuv.py"],
33 // optional if /config/plugins.js -> email.settings.defaultFrom is set
34 from: "from@example.com",
35 // optional if /config/plugins.js -> email.settings.defaultReplyTo is set
36 replyTo: "reply@example.com",
37 // optional array of files
38 attachments: [],
39 },
40 {
41 // required - Ref ID defined in the template designer (won't change on import)
42 templateReferenceId: 20,
43 // If provided here will override the template's subject.
44 // Can include variables like `Thank you for your order {{= USER.firstName }}!`
45 subject: `Thank you for your order`,
46 },
47 {
48 // this object must include all variables you're using in your email template
49 USER: { firstName: "John", lastName: "Doe" },
50 order: {
51 products: [
52 { name: "Article 1", price: 9.99 },
53 { name: "Article 2", price: 5.55 },
54 ],
55 },
56 shippingCost: 5,
57 total: 20.54,
58 }
59 );
60 strapi.log.info("Email sent");
61 } catch (error) {
62 strapi.log.error(error);
63 }
64 },
65};
This is what the email looked like in the MailDev client
Here is a list of the services that the plugin provides. You can call upon them in your controllers or services(or wherever you want).
sendTemplatedEmail
You will probably use this one a lot.
1await strapi
2 .plugin("email-designer-5")
3 .service("email")
4 .sendTemplatedEmail(EMAIL_OPTIONS_OBJECT, EMAIL_TEMPLATE_OBJECT, DATA);
compose
I didn't get why this service was deprecated in the original plugin, but i found it useful for sending PDF data to my frontend.
1await strapi.plugin("email-designer-5").service("email").compose({ templateReferenceId, data });
This returns the email HTML and Text with the data merged.
1{
2 html: "<html>...</html>",
3 text: "..."
4}
I am SUPER new to React. I have been using Nuxt all my life. If you see where I could have done something better in the admin area, please let me know. I am open to suggestions.
Just fork the repo, make your changes, and submit a PR. I will review it as soon as I can. I am open to learning new things.
MIT
I mean, I am not the original author of the plugin. I just made it compatible with Strapi v5. So, I am not sure if I can license it. But, I will keep it MIT for now.
Image of the Core Tab in the Admin UI
Image of the Custom Email Tab in the Admin UI
Image of the Editor wit imported design
Image of Email in MailDev
npm install strapi-plugin-email-designer-5
Check out the available plugin resources that will help you to develop your plugin or provider and get it listed on the marketplace.