Email functionality is a staple in many applications, but with so many options available, it can be a bit overwhelming, right? There are various email delivery services, some frameworks have built-in email capabilities, and then there are security considerations and monitoring to think about. It's quite a lot to consider!
In this post, I'll share a recent implementation of an email delivery feature using Nest.js and Google Cloud. I'll walk you through the documentation we consulted during our research and provide some insights into the implementation details. My hope is that this will be helpful for those of you working with Nest.js backends.
Our Final Setup
Here's what we ultimately decided on:
- We used SendGrid as our email delivery service.
- We created an injectable module for email delivery using nest-modules/mailer, allowing us to use dependency injection where needed.
- We wrote email templates using Handlebars, which allows us to pass necessary variables when calling the template.
The Technology Selection Process
We had already decided to use Nest.js and Google Cloud, so our investigation focused on the following:
- Determining how to best provide email functionality within Nest.js
- Identifying email delivery options that would work well (and easily) with Google Cloud
- Deciding on a template engine for our emails (if necessary)
By clarifying these points, we were able to select an email delivery solution that was compatible with both Nest.js and Google Cloud.
How to Implement Email Functionality in Nest.js
Our team had already done some preliminary research, and we were leaning towards using nest-module/mailer. While we say "research," we essentially decided to proceed with nest-modules/mailer as our base implementation.
https://github.com/nest-modules/mailer
For example, here are some similar articles we found:
https://zenn.dev/yuu104/articles/8b8d7363b5dd5f
https://myprg.dev/posts/nestjs-jsx-mail
We also found other approaches, including creating custom modules that call SDKs directly:
https://zenn.dev/doshirote/articles/299796eec8ccae#nestjs%E3%81%A7%E5%AE%9F%E8%A3%85
https://iwaking.com/blog/how-to-send-emails-using-ejs-template-engine-with-nest-js
Email Templates
nest-module/mailer supports three libraries for templating:
After considering the options (referencing articles like this one), we chose Handlebars. While Pug was appealing, we liked that Handlebars is readable to anyone who knows HTML, and its similarity to other template engines like Jinja makes it accessible to developers coming from other languages.
https://nest-modules.github.io/mailer/docs/mailer.html#configuration
Email Delivery Options in Google Cloud
Google Cloud officially recommends three services for email delivery:
- Mailjet: https://cloud.google.com/compute/docs/tutorials/sending-mail/using-mailjet
- Mailgun: https://cloud.google.com/compute/docs/tutorials/sending-mail/using-mailgun
- SendGrid: https://cloud.google.com/compute/docs/tutorials/sending-mail/using-sendgrid
Our Google Cloud stack is quite simple - we're just deploying our application to Cloud Run. We didn't want to add extra configurations or create additional resources for this feature, nor did we want to complicate our operations. After reviewing the documentation:
- Mailjet: We'd need to verify how well SMTP configuration within an instance would work with Cloud Run.
- Mailgun: It wasn't clear how well we could replicate the Postfix configuration for using Mailgun as a mail relay in Cloud Run.
- SendGrid: The official documentation suggested we could get started just by installing the SendGrid library.
Given these considerations, SendGrid emerged as our top choice for email delivery.
Implementation Details
For a smooth implementation, I recommend following the approach outlined in this article, which covers a typical implementation using nest-modules/mailer:
https://notiz.dev/blog/send-emails-with-nestjs
Here, I'll explain the additional configuration needed to use SendGrid with nest-module/mailer. To send emails through SendGrid, you need to modify the transport host, port, and auth information in the MailerModule's forRoot definition. This allows nest-module/mailer to use SendGrid for email delivery.
https://www.twilio.com/blog/send-smtp-emails-node-js-sendgrid
Here's an example configuration:
import { Module } from '@nestjs/common'
import { MailerModule } from '@nestjs-modules/mailer'
// This is a workaround for cases where the Handlebars adapter doesn't work properly during Jest execution
let adapter = null
if (!process.env.JEST_WORKER_ID) {
import('@nestjs-modules/mailer/dist/adapters/handlebars.adapter').then(
module => {
adapter = module.HandlebarsAdapter
},
)
}
@Module({
imports: [
MailerModule.forRoot({
// The transport configuration below is crucial
transport: {
host: 'smtp.sendgrid.net',
port: 587,
auth: {
user: 'apikey',
pass: process.env.SENDGRID_API_KEY,
},
},
defaults: {
from: process.env.SENDGRID_FROM_MAIL,
},
template: adapter
? {
dir: __dirname + '/templates',
adapter,
options: {
strict: true,
},
}
: undefined,
}),
],
})
With this setup, you should be ready to start sending emails using Nest.js, Google Cloud, and SendGrid!
I hope this guide helps you in implementing your own email delivery system. If you have any questions or run into any issues, feel free to reach out or leave a comment below.
Happy coding!
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.