Notification
SMTP
SMTP email notification provider — send transactional emails via any standard SMTP server.
The @commercejs/notification-smtp package implements the NotificationProvider interface for delivering emails via SMTP using nodemailer. Works with Gmail, Amazon SES, Postfix, Mailgun, or any standard SMTP server.
Installation
pnpm add @commercejs/notification-smtp
Quick Start
import { createSmtpProvider } from '@commercejs/notification-smtp'
const smtp = createSmtpProvider({
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: { user: 'you@gmail.com', pass: 'app-password' },
from: 'My Store <noreply@mystore.com>',
})
With CommerceJS
import { createCommerce } from '@commercejs/core'
const commerce = createCommerce({
adapter,
notifications: { smtp },
notificationRules: [
{
event: 'order.created',
channel: 'email',
provider: 'smtp',
template: 'order_confirmation',
buildMessage: (payload) => ({
to: payload.order.customer.email,
subject: 'Order confirmed',
html: '<h1>Thank you for your order!</h1>',
}),
},
],
})
Configuration
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | — | SMTP server hostname |
port | number | Yes | — | SMTP port |
secure | boolean | No | false | Use implicit TLS (port 465) |
auth.user | string | No | — | SMTP username |
auth.pass | string | No | — | SMTP password or app password |
from | string | Yes | — | Default sender address |
replyTo | string | No | — | Reply-to address |
connectionTimeout | number | No | 10000 | Connection timeout (ms) |
socketTimeout | number | No | 10000 | Socket timeout (ms) |
transporter | Transporter | No | — | Custom nodemailer transporter |
Common SMTP Servers
| Provider | Host | Port | Secure | Notes |
|---|---|---|---|---|
| Gmail | smtp.gmail.com | 587 | false | Requires app password |
| Amazon SES | email-smtp.{region}.amazonaws.com | 587 | false | IAM SMTP credentials |
| Outlook | smtp-mail.outlook.com | 587 | false | App password or OAuth |
| Mailgun | smtp.mailgun.org | 587 | false | SMTP credentials from dashboard |
| Postfix | localhost | 25 | false | Local mail server |
Usage Examples
HTML Email
await smtp.send('email', {
to: 'customer@example.com',
subject: 'Your order has shipped!',
html: '<h1>Shipping Notification</h1><p>Your order is on the way.</p>',
})
Plain Text Email
await smtp.send('email', {
to: 'customer@example.com',
subject: 'Order update',
text: 'Your order has been delivered.',
})
Multipart (HTML + Text Fallback)
await smtp.send('email', {
to: 'customer@example.com',
subject: 'Welcome!',
html: '<h1>Welcome to our store</h1>',
text: 'Welcome to our store',
})
SMTP vs Resend
| Aspect | SMTP | Resend |
|---|---|---|
| Setup | Host/port/auth config | API key only |
| Speed | Depends on server | Fast (HTTP API) |
| Deliverability | You manage reputation | Resend manages |
| Cost | Free with own server | Free tier + paid |
| Edge support | Node.js only | Works on edge |
| Best for | Self-hosted, existing infrastructure | Quick setup, managed delivery |
Error Handling
All errors are caught and returned as NotificationResult:
const result = await smtp.send('email', {
to: 'customer@example.com',
subject: 'Test',
text: 'Hello',
})
if (!result.success) {
console.error(result.error)
// "Connection refused" or "Invalid login: 535 Authentication failed"
}
Testing
The package includes 11 tests with mocked transporters:
pnpm vitest run
Tests cover send success, plain text, HTML, multipart, reply-to, channel rejection, missing fields, auth errors, transport errors, and custom message IDs.