Agent skill
nodemailer
Sends emails from Node.js applications using SMTP or other transports with Nodemailer. Use when implementing email functionality with full control over transport configuration.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/nodemailer-mgd34msu-goodvibes-plugin
SKILL.md
Nodemailer
Node.js email sending library. Works with SMTP, Amazon SES, and other transports. Zero dependencies, full Unicode support.
Quick Start
npm install nodemailer
Basic SMTP Setup
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
secure: false, // true for 465, false for 587
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
// Send email
await transporter.sendMail({
from: '"My App" <[email protected]>',
to: '[email protected]',
subject: 'Hello',
text: 'Plain text content',
html: '<b>HTML content</b>',
});
Transport Configuration
Gmail
// Use App Password (not regular password)
// Enable 2FA, then generate App Password in Google Account settings
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '[email protected]',
pass: 'your-app-password', // 16-character app password
},
});
Gmail with OAuth2
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: '[email protected]',
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
refreshToken: process.env.GOOGLE_REFRESH_TOKEN,
},
});
Outlook/Office365
const transporter = nodemailer.createTransport({
host: 'smtp.office365.com',
port: 587,
secure: false,
auth: {
user: '[email protected]',
pass: 'your-password',
},
});
Amazon SES
import { SES } from '@aws-sdk/client-ses';
const transporter = nodemailer.createTransport({
SES: {
ses: new SES({
region: 'us-east-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
}),
aws: { SendRawEmailCommand },
},
});
Resend SMTP
const transporter = nodemailer.createTransport({
host: 'smtp.resend.com',
port: 465,
secure: true,
auth: {
user: 'resend',
pass: process.env.RESEND_API_KEY,
},
});
SendGrid SMTP
const transporter = nodemailer.createTransport({
host: 'smtp.sendgrid.net',
port: 587,
secure: false,
auth: {
user: 'apikey',
pass: process.env.SENDGRID_API_KEY,
},
});
Message Options
const message = {
// Sender
from: '"Sender Name" <[email protected]>',
// Recipients
to: '[email protected]',
// Or multiple
to: '[email protected], [email protected]',
// Or with names
to: '"User One" <[email protected]>, "User Two" <[email protected]>',
// CC and BCC
cc: '[email protected]',
bcc: '[email protected]',
// Reply-to
replyTo: '[email protected]',
// Subject
subject: 'Hello World',
// Content
text: 'Plain text body',
html: '<h1>HTML body</h1>',
// Priority
priority: 'high', // 'high', 'normal', 'low'
// Custom headers
headers: {
'X-Custom-Header': 'value',
},
// Message-ID
messageId: '<[email protected]>',
// References (for threading)
references: '<[email protected]>',
inReplyTo: '<[email protected]>',
};
await transporter.sendMail(message);
Attachments
const message = {
from: '[email protected]',
to: '[email protected]',
subject: 'With attachments',
text: 'See attachments',
attachments: [
// From file
{
filename: 'document.pdf',
path: './files/document.pdf',
},
// From buffer
{
filename: 'data.json',
content: Buffer.from(JSON.stringify({ hello: 'world' })),
},
// From string
{
filename: 'text.txt',
content: 'Hello World',
},
// From URL
{
filename: 'image.png',
path: 'https://example.com/image.png',
},
// Embedded image (for HTML)
{
filename: 'logo.png',
path: './logo.png',
cid: 'logo@myapp', // Reference in HTML as <img src="cid:logo@myapp">
},
],
};
await transporter.sendMail(message);
Embedded Images
const message = {
from: '[email protected]',
to: '[email protected]',
subject: 'With embedded image',
html: `
<h1>Hello</h1>
<img src="cid:logo@myapp" alt="Logo" />
`,
attachments: [
{
filename: 'logo.png',
path: './logo.png',
cid: 'logo@myapp',
},
],
};
Verify Connection
Test configuration before sending.
try {
await transporter.verify();
console.log('SMTP connection successful');
} catch (error) {
console.error('SMTP connection failed:', error);
}
Error Handling
try {
const info = await transporter.sendMail(message);
console.log('Message sent:', info.messageId);
} catch (error) {
if (error.responseCode === 550) {
console.error('Recipient rejected');
} else if (error.code === 'ECONNECTION') {
console.error('Connection failed');
} else if (error.code === 'EAUTH') {
console.error('Authentication failed');
} else {
console.error('Error:', error.message);
}
}
Pooled Connections
For high-volume sending, reuse connections.
const transporter = nodemailer.createTransport({
pool: true,
host: 'smtp.example.com',
port: 587,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
maxConnections: 5,
maxMessages: 100,
});
// Close pool when done
transporter.close();
With React Email
import nodemailer from 'nodemailer';
import { render } from '@react-email/components';
import WelcomeEmail from './emails/welcome';
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
async function sendWelcomeEmail(user) {
const html = await render(WelcomeEmail({
name: user.name,
actionUrl: 'https://myapp.com/start',
}));
await transporter.sendMail({
from: '"MyApp" <[email protected]>',
to: user.email,
subject: `Welcome, ${user.name}!`,
html,
});
}
Next.js API Route
// app/api/contact/route.ts
import { NextResponse } from 'next/server';
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT || '587'),
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
export async function POST(request: Request) {
const { name, email, message } = await request.json();
try {
await transporter.sendMail({
from: process.env.SMTP_FROM,
to: process.env.CONTACT_EMAIL,
replyTo: email,
subject: `Contact form: ${name}`,
text: `From: ${name} <${email}>\n\n${message}`,
html: `
<p><strong>From:</strong> ${name} <${email}></p>
<p>${message.replace(/\n/g, '<br>')}</p>
`,
});
return NextResponse.json({ success: true });
} catch (error) {
console.error('Email error:', error);
return NextResponse.json(
{ error: 'Failed to send email' },
{ status: 500 }
);
}
}
Testing with Ethereal
Free fake SMTP for testing - no emails actually sent.
// Create test account
const testAccount = await nodemailer.createTestAccount();
const transporter = nodemailer.createTransport({
host: 'smtp.ethereal.email',
port: 587,
secure: false,
auth: {
user: testAccount.user,
pass: testAccount.pass,
},
});
const info = await transporter.sendMail({
from: '[email protected]',
to: '[email protected]',
subject: 'Test',
text: 'Test email',
});
// Preview URL
console.log('Preview:', nodemailer.getTestMessageUrl(info));
Environment Variables
# SMTP Configuration
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-username
SMTP_PASS=your-password
SMTP_FROM="My App" <[email protected]>
# Or for Gmail
[email protected]
GMAIL_APP_PASSWORD=your-app-password
Common Transports
| Provider | Host | Port | Secure |
|---|---|---|---|
| Gmail | smtp.gmail.com | 465 | true |
| Outlook | smtp.office365.com | 587 | false |
| Yahoo | smtp.mail.yahoo.com | 465 | true |
| SendGrid | smtp.sendgrid.net | 587 | false |
| Mailgun | smtp.mailgun.org | 587 | false |
| Amazon SES | email-smtp.{region}.amazonaws.com | 465 | true |
Best Practices
- Use environment variables - Never hardcode credentials
- Verify connection - Test before sending in production
- Use pooling - For high-volume sending
- Handle errors - Implement proper error handling
- Use OAuth2 - More secure than passwords for Gmail
- Test with Ethereal - Free testing without sending real emails
- Set proper From - Use verified sender addresses
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?