Email
Mailgun

Setting Up Mailgun

This document outlines the steps to integrate Mailgun into your project using Next.js.

0.1. Create a Mailgun Account

To use Mailgun, you need to create an account. You can do this by visiting the Mailgun website (opens in a new tab).

0.2. Create a mailgun domain

0.3. Create a Mailgun Sending API Key

Once you have created an account, you need to create an Sending API key.

  1. Navigate to the domain dashboard (opens in a new tab).
  2. Open the domain settings dropdown.
  3. Navigate to the "Sending API Keys" tab.
  4. If you have permission to create a new API key, click the "Create API Key" button.

1. Install the Mailgun and FormData NPM Packages

To get started with Mailgun, you need to install the mailgun.js (opens in a new tab) package. Run the following command in your project directory:

npm install mailgun.js form-data --save

NOTE: starting from version 3.0 you need to pass FormData (we need this to keep library universal). For node.js you can use form-data library.

2. Create a Mailgun Client

import Mailgun from "mailgun.js";
import formData from "form-data";
 
const mailgun = new Mailgun(formData);
const mailgunClient = mailgun.client({
  username: "api",
  key: process.env.MAILGUN_API_KEY,
});

Make sure you have your environment variables set up in your .env file or through your deployment configuration:

MAILGUN_API_KEY=your-api-key
MAILGUN_DOMAIN=your-domain

2. Email data

const emailData = {
  from: "no-reply@upheave.tech", // or process.env.MAILGUN_DOMAIN
  to: "your-email@example.com, jon.doe@upheave.tech",
  subject: `email subject`,
  template: "your-template-name",
  "o:tag": "my-tag",
  "h:X-Mailgun-Variables": JSON.stringify({
    variable1: "value1",
    variable2: "value2",
  }),
};

2.1. h:X-Mailgun-Variables

The h:X-Mailgun-Variables header is used to pass custom variables to the email template. This can be useful for personalizing the email content based on the user's preferences or other information.

2.2. o:tag

The o:tag in Mailgun can be useful for tracking and filtering emails in the Mailgun dashboard.



3. Sending email

For sending emails, you need to create a Mailgun instance and call the messages.create method.

try {
  const response = await mailgunClient.messages.create(process.env.MAILGUN_DOMAIN, emailData);
  // do something with the response, or don't...
} catch (error: any) {
  console.error(error);
}

4. Mailgun template

Mailgun allows you to use templates for your emails. Templates help in maintaining a consistent format and design for your emails. You can create templates in the Mailgun dashboard and then use them in your project.



4.1. Create template


Define your template name inside Template details section and use it in your email data.

const emailData = {
  // from: "no-reply@upheave.tech", // or process.env.MAILGUN_DOMAIN
  // to: "your-email@example.com, jon.doe@upheave.tech",
  // subject: `email subject`,
  template: "your-template-name",
  // "o:tag": "my-tag",
  // "h:X-Mailgun-Variables": JSON.stringify({
  //   variable1: "value1",
  //   variable2: "value2",
  // }),
};

4.2. Edit template

4.3. Template example

const emailData = {
  // from: "no-reply@upheave.tech", // or process.env.MAILGUN_DOMAIN
  // to: "your-email@example.com, jon.doe@upheave.tech",
  // subject: `email subject`,
  // template: "your-template-name",
  // "o:tag": "my-tag",
  "h:X-Mailgun-Variables": JSON.stringify({
    variable1: "value1",
    variable2: "value2",
  }),
};

Variables in the template are defined with doble curly braces {{ variable }}.

5. Mailgun service example

Example is from City-Island project. Notification email service for lease expiration and renewal.

import Mailgun, { Interfaces, MailgunMessageData } from "mailgun.js";
import formData from "form-data";
import logger from "@/logger";
 
export interface IMailgunService {
  sendMail(data: MailgunMessageData): Promise<void>;
}
 
export class MailgunService implements IMailgunService {
  private mailgunClient: Interfaces.IMailgunClient;
  private apiKey: string;
  private domain: string;
 
  constructor() {
    this.apiKey = process.env.MAILGUN_API_KEY || "";
    this.domain = process.env.MAILGUN_DOMAIN || "";
 
    if (!this.apiKey || !this.domain) {
      throw new Error("Mailgun API key and domain must be provided");
    }
 
    const mailgun = new Mailgun(formData);
    this.mailgunClient = mailgun.client({
      username: "api",
      key: this.apiKey,
    });
  }
 
  async sendMail(data: MailgunMessageData): Promise<void> {
    try {
      const { from, to, subject, template } = data;
 
      if (!from || !to || !subject || !template) {
        throw new Error("Missing required mail data fields");
      }
 
      await this.mailgunClient.messages.create(this.domain, data);
    } catch (e: any) {
      logger.error(e, { module: "Mailgun email service" });
      throw e;
    }
  }
}

5.1. Sending email

Sending email is very simple. You just need to pass email data to the service.

await mailgunService.sendMail(emailData);

5.2. Email data

Email data is an object with the following properties:

const emailData = {
  from: string;
  to: string;
  subject: string;
  template: string;
  "o:tag": string;
  "h:X-Mailgun-Variables": string;
};
// h:X-Mailgun-Variables
const leaseData = {
  leaseId: string;
  leaseUrl: string;
  tenant: string;
  leaseStartDate: string;
  leaseEndDate: string;
  buildings: string;
  offices: string;
};

5.3. Lease expiration template