Antonio
Posted on December 1, 2020
Sending emails is a fundamental feature in most projects. From welcoming new users to sending notifications and reminders, it's something that I find myself doing in every project.
I've been using Strapi for a few months now as it allows me to create APIs easily and fast and, even though it includes a default plugin to send emails out the box, it's not the best option to use in Production. There are multiple plugins for different email providers but in this article, I'll show you how to use a plugin that works with any provider.
Why you shouldn't use Strapi's default email plugin
Why do we need to install a new plugin if Strapi has one out of the box? As they mention in the documentation, Strapi uses sendmail as a default provider, which basically means that the emails are sent directly from the local server running Strapi.
You might use this during development but in Production it can cause you some issues:
- It's not 100% reliable
- Common mail servers, like Gmail, Outlook and Yahoo will block your emails if they are not being sent from a trusted server.
- Your server might not have sendmail installed
- Sendmail won't probably work if you are deploying your Strapi application with Docker
To avoid these issues, it's better to use an external provider. In the Strapi documentation they have an example using Sendgrid with its own specific plugin. Although it's a great platform, Sendgrid's free tier is very limited (only 100 emails/day) so I prefer to use SendinBlue (free 300 emails/day) or for more email demanding projects, ElasticEmail ($0.09 per 1000 emails).
Although there is a specific plugin for SendinBlue, I don't like the idea of my application depending on one specific third party like that and I'm not sure if I'll be using the same provider forever, so I prefer to use a plugin that is provider agnostic. And what do most email providers have in common? They all support the SMTP protocol, so that's what we'll use.
For this article, I'd assume we'll be using SendinBlue so go ahead and create a free account. You can find the SMTP details in your account settings > SMTP & API.
Plugin install and setup
The first thing you'll need is a scaffolded Strapi project. You can check how to create one in this article.
The plugin we're going to use is strapi-provider-email-nodemailer and, as I mentioned I choose this one for multiple reasons:
- It's provider agnostic
- Uses SMTP protocol
- Super easy to configure and use
- Migrating to a different provider is super simple
To install it, run npm i strapi-provider-email-nodemailer
. To configure it I recommend to use an .env file as your server details will probably be different in DEV and PROD. To checkout how to use .env files in Strapi, check this section of the docs.
In our .env file we'll add the following variables:
EMAIL_PROVIDER=nodemailer
EMAIL_SMTP_HOST=smtp.zzzz.zzzzz
EMAIL_SMTP_PORT=587
EMAIL_SMTP_USER=xxXXXXxxxxXXX
EMAIL_SMTP_PASS=yyyYYYYYyyyYYYY
EMAIL_ADDRESS_FROM=aaaaaa@bbbbbb.com
EMAIL_ADDRESS_REPLY=ccccccc@dddddd.com
Sendinblue's SMTP host is
smtp-relay.sendinblue.com
and port is 587.
Next step is to configure the plugin in the config/plugins.js file:
// File: config/plugins.js
module.exports = ({ env }) => ({
// ...
email: {
provider: env('EMAIL_PROVIDER'),
providerOptions: {
host: env('EMAIL_SMTP_HOST', 'smtp.example.com'),
port: env('EMAIL_SMTP_PORT', 587),
auth: {
user: env('EMAIL_SMTP_USER'),
pass: env('EMAIL_SMTP_PASS'),
},
},
settings: {
defaultFrom: env('EMAIL_ADDRESS_FROM'),
defaultReplyTo: env('EMAIL_ADDRESS_REPLY'),
},
},
// ...
})
As you can see, the configuration is pretty straight forward and we just have to assign the server and authentication details that we included in the env before.
If you don't want to use an env file, you can populate these variables using
process.env.YOUR_ENV_VARIABLE
instead ofenv('YOUR_ENV_VARIABLE')
or, if you're testing locally, directly assigning the values but remember not to commit these to your repository for security reasons.
Sending emails
To make this example as simple as possible, I'll create an endpoint in our API that automatically sends an email. We'll create the following files inside api folder:
- /api/email/config/routes.json
// /api/email/config/routes.json
{
"routes": [
{
"method": "POST",
"path": "/emails",
"handler": "Email.send",
"config": {}
}
]
}
This will create a new POST endpoint /emails in our API, and the requests will be handled by the send method inside the Email controller, which we will create next:
- /api/email/controllers/Email.js
// File /api/email/controllers/Email.js
'use strict'
/**
* Read the documentation () to implement custom controller functions
*/
module.exports = {
/**
* Sends an email to the recipient in the body of the request
*/
send: async (ctx) => {
const body = ctx.request.body
const sendTo = body.email
strapi.log.debug(`Trying to send an email to ${sendTo}`)
try {
const emailOptions = {
to: sendTo,
subject: 'This is a test',
html: `<h1>Welcome!</h1><p>This is a test HTML email.</p>`,
}
await strapi.plugins['email'].services.email.send(emailOptions)
strapi.log.debug(`Email sent to ${sendTo}`)
ctx.send({ message: 'Email sent' })
} catch (err) {
strapi.log.error(`Error sending email to ${sendTo}`, err)
ctx.send({ error: 'Error sending email' })
}
},
}
The send method receives a POST request with the email in the body. We create an emailOptions object that contains the properties for destination address (to), subject and html as the body of the email. Then we just have to use the the strapi.plugins['email'].services.email.send method and pass it the emailOptions object.
If you need to add attachements, bcc or other email options, you can check the nodemailer message configuration here. You'd just need to add the options you need in the emailOptions object ๐
Now if we start our Strapi application with npm run develop
and send a POST request to /emails with Postman or cURL, our email will be sent ๐ฌ
# Send POST request to /emails via cURL
curl --location --request POST 'localhost:1337/emails' \
--header 'Content-Type: application/json' \
--data-raw '{"email": "example@email.com"}'
Conclusion
This is a very basic example to show you how to programmatically send emails with Strapi via SMTP. In my case I normally trigger emails in cron jobs or in an authentication protected endpoints after users do a certain action.
Important: You shouldn't have a public endpoint in your API that triggers emails as it can be easily exploited and you could be charged by your email provider.
I like using nodemailer because it's provider agnostic and it allows me to easily change providers by just changing the server and credential details in my env file. In addition, it supports Amazon SES transport so you can use that option. You can find more info about how to use nodemailer with SES here.
If you liked this article, you can follow me on Twitter where I share dev tips, interesting articles and updates about the progress of my projects ๐ค
Happy coding!
This article was originally posted in my blog where you can find other articles about web development focused on Node.js, Vue, Laravel and anything related with product development.
Posted on December 1, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.