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>".