perseidesperseides
notification-nodemailer

Basic Usage

Learn how to send email notifications using the Nodemailer provider in Medusa.

Sending Email Notifications

Once configured, you can send email notifications using the Notification Module.

Simple Text Email

import { Modules } from "@medusajs/framework/utils"

// Inside an API route, workflow, or subscriber
const notificationService = container.resolve(Modules.NOTIFICATION)

await notificationService.createNotifications({
  to: "customer@example.com",
  channel: "email",
  template: "order-confirmation", // ℹ️ This is a mandatory field for Medusa, but not used inside the Nodemailer provider
  content: {
    subject: "Order Confirmation",
    text: "Thank you for your order! Your order #12345 has been confirmed."
  }
})

HTML Email

await notificationService.createNotifications({
  to: "customer@example.com",
  template: "welcome",
  channel: "email",
  content: {
    subject: "Welcome to Our Store",
    html: `
      <h1>Welcome!</h1>
      <p>Thank you for creating an account.</p>
      <a href="https://example.com/shop">Start Shopping</a>
    `
  }
})

Common Use Cases

Custom From Address

You can override the default from address for specific emails:

await notificationService.createNotifications({
  from: "support@example.com", // Override default from
  to: "customer@example.com",
  channel: "email",
  template: "support-response",
  content: {
    subject: "Support Response",
    text: "We've received your support request..."
  }
})

Email with Attachments

You can attach files to emails. The plugin supports both regular attachments and inline images.

Regular Attachment

import QRCode from "qrcode"

const qrBuffer = await QRCode.toBuffer("VOUCHER-123")

// Convert to binary string (Medusa's recommended format)
const binaryString = [...qrBuffer]
  .map((byte) => byte.toString(2).padStart(8, "0"))
  .join("")

await notificationService.createNotifications({
  to: "customer@example.com",
  channel: "email",
  template: "voucher",
  content: {
    subject: "Your Voucher",
    html: "<p>Please find your QR code attached.</p>"
  },
  attachments: [
    {
      content: binaryString,
      filename: "voucher-qr.png",
      content_type: "image/png",
      disposition: "attachment",
    }
  ]
})

Inline Image (CID)

To embed an image directly in the email body, use the disposition: "inline" option with an id (Content-ID) that you reference in your HTML:

import QRCode from "qrcode"

const dataUrl = await QRCode.toDataURL("VOUCHER-123")
// Strip the data URL prefix to get pure base64
const base64Content = dataUrl.replace(/^data:image\/png;base64,/, "")

await notificationService.createNotifications({
  to: "customer@example.com",
  channel: "email",
  template: "voucher",
  content: {
    subject: "Your Voucher",
    html: `
      <h1>Your Voucher</h1>
      <p>Scan this QR code:</p>
      <img src="cid:qr-code" alt="QR Code" width="200" height="200" />
    `
  },
  attachments: [
    {
      id: "qr-code",           // Content-ID for referencing in HTML
      content: base64Content,  // base64 string
      filename: "qr-code.png",
      content_type: "image/png",
      disposition: "inline",   // Embed in email body
    }
  ]
})

The id field maps to the Content-ID (CID) header. Reference it in your HTML with src="cid:<id>".

On this page