Send beautiful emails with Next.js, Postmark, and Mailing

January 28, 2023 3 min read


Prerequisites

To send emails with Postmark, you must first sign up for an account; the free developer plan will work just fine.

Mailing is free and open-source, so there are no prerequisites.

Add Postmark

First, create a new server in Postmark and get the API token by going to Servers → Your server → API Tokens. You will need this token to be able to send emails.

Install the Postmark package:

yarn add postmark

Next, add the following environment variables to your .env file:

POSTMARK_API_TOKEN=your-api-token
SMTP_HOST=smtp.postmarkapp.com
SMTP_PORT=587
SMTP_USERNAME=your-api-token
SMTP_PASSWORD=your-api-token
SMTP_FROM=Your Name <no_reply@your-domain.com>

Add Nodemailer (Optional)

You can use any email-sending package, but I'll be using Nodemailer in this guide. If you don't have it installed, you can add it to your project by running the following command:

yarn add nodemailer

Add Mailing

Install the following packages:

yarn add mailing-core next react react-dom

yarn add --dev mailing

Let's set up Mailing. Run the following command:

npx mailing or npx mailing --typescript if you are using TypeScript.

You should now have an emails folder in your project root and the Mailing dev server should be running, so that you can live-preview your emails in the browser.

Let's configure the SMTP transport aka instruct Mailing to use Postmark to send emails. Open emails/index.ts and replace it with the following:

emails/index.ts
import nodemailer from 'nodemailer'
import { buildSendMail } from 'mailing-core'

const sendMail = buildSendMail({
	transport: nodemailer.createTransport({
		host: process.env.SMTP_HOST,
		port: process.env.SMTP_PORT,
		auth: {
			user: process.env.POSTMARK_API_TOKEN,
			pass: process.env.POSTMARK_API_TOKEN,
		},
	}),
	defaultFrom: process.env.SMTP_FROM,
	configPath: './mailing.config.json',
})

export default sendMail

Tada! You can now send emails using the sendMail function. Let's create a simple magic link email template to test it out with Auth.js.

Create the magic link email template

Mailing uses MJML, which is great since MJML takes the pain away from building responsive emails.

Create a new file VerifyEmail.tsx in emails/ and add the following code:

emails/VerifyEmail.tsx
import React, { ReactElement } from 'react'
import { MjmlSection, MjmlColumn } from 'mjml-react'
import { Template } from 'mailing-core'
import Button from './components/Button'
import Text from './components/Text'
import BaseLayout from './components/BaseLayout'
import { spacing } from './theme'

type VerifyEmailProps = {
	url: string
}

const VerifyEmail: Template<VerifyEmailProps> = ({ url }) => {
	return (
		<BaseLayout width={352}>
			<MjmlSection cssClass='gutter'>
				<MjmlColumn>
					<Text paddingTop={spacing.s5} paddingBottom={spacing.s5}>
						Click the button below to verify your email and log in to your
						account.
					</Text>
					<Button href={url}>Verify your email</Button>
				</MjmlColumn>
			</MjmlSection>
		</BaseLayout>
	)
}
VerifyEmail.subject = 'Magic link'
export default VerifyEmail

Preview:

Verify email template preview

Using the verify email template to send a verification email from Auth.js

Open [...nextauth].tsx and add the following code:

pages/api/auth/[...nextauth].tsx
import sendMail from '../../../emails/index'
import Welcome from '../../../emails/Welcome'
//...

export const authOptions: NextAuthOptions = {
	//...
	providers: [
		EmailProvider({
			//...
			async sendVerificationRequest({ identifier, url }) {
				try {
					await sendMail({
						subject: 'Magic link',
						to: identifier,
						component: <Welcome url={url} />,
					})
				} catch (error) {
					console.error(error)
				}
			},
		}),
	],
	//...
}
export default NextAuth(authOptions)

As you can see, we are using the sendMail function to send the verification email. The component prop is the email template we created earlier.

Conclusion

And that's it! You can now send beautiful auth emails using Next.js, Mailing, and Postmark.