DEV Community

Cover image for Easily send emails in Strapi with any provider
Antonio
Antonio

Posted on • Edited on • Originally published at antonioufano.com

Easily send emails in Strapi with any provider

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.

Sendinblue SMTP connection details

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
Enter fullscreen mode Exit fullscreen mode

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'),
    },
  },
  // ...
})
Enter fullscreen mode Exit fullscreen mode

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 of env('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": {}
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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' })
    }
  },
}
Enter fullscreen mode Exit fullscreen mode

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"}'
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)