はじめに
会員登録の確認メール、パスワードリセット、注文完了通知。Webアプリを作っていると、 「Node.jsからメールを送る」場面は必ずと言っていいほど出てきます。ところが、いざ実装 しようとすると悩みが尽きません。開発中はどこにメールを送ればいいのか、本番ではSMTP とAmazon SESのどちらを使うのか、添付ファイルやHTMLメールはどう組み立てるのか——。
こうした悩みを一手に引き受けてくれるのが、Node.jsのメール送信ライブラリ Nodemailerです。2010年から使われ続けている定番パッケージでありながら、 2026年現在もセキュリティ修正を含むアップデートが続けられており、依存パッケージ ゼロという身軽さも変わっていません。トランスポート(送信経路)を差し替えるだけで、 ローカルのテスト送信から本番のSMTP・SES送信まで同じAPIで扱えるのが最大の魅力です。
Nodemailerとは
Nodemailerは、Node.jsアプリケーションからメールを送信するためのモジュールです。
createTransport() で送信経路(トランスポート)を作り、sendMail() でメールを
送るというシンプルな2ステップの設計になっており、SMTPサーバーへの接続からMIME
メッセージの組み立てまでを内部で処理してくれます。
主な特徴
- 依存パッケージがゼロ - 単体のパッケージで完結しており、サプライチェーンリスクを抑えられます
- 複数のトランスポートに対応 - SMTP・Amazon SES・sendmail・ストリーム出力などを同じAPIで切り替えられます
- DKIM署名とOAuth2認証をサポート - なりすまし対策やGmail・Microsoft 365といったOAuth2必須のサービスにも対応できます
- Etherealによるテスト送信 -
createTestAccount()で使い捨てのSMTPアカウントを即座に発行し、実際に送らずに内容を確認できます
インストール
npmから通常のパッケージとしてインストールします。
npm install nodemailer
TypeScriptで型定義を使いたい場合は、あわせて型パッケージも入れておきます。
npm install --save-dev @types/nodemailer
基本的な使い方
まずは最小構成でメールを1通送る例です。nodemailer.createTransport() にSMTPの
接続情報を渡してトランスポートを作り、transporter.sendMail() に送信内容を渡すだけで、
Nodemailerが接続からメッセージ組み立てまでを処理してくれます。
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
secure: false, // 465番ポートを使う場合はtrue
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
const info = await transporter.sendMail({
from: '"通知担当" <noreply@example.com>',
to: "user@example.com",
subject: "登録が完了しました",
text: "ご登録ありがとうございます。",
html: "<p>ご登録ありがとうございます。</p>",
});
console.log("送信結果:", info.messageId);
sendMail() は text と html を両方渡せるので、HTML未対応のメールクライアント
向けにプレーンテキスト版も同時に用意しておくのが定石です。認証情報はコード中に
直書きせず、環境変数から読み込むようにしてください。
実践的なユースケース
Etherealで開発中のメールをプレビューする
本番のメールサーバーにつなぐ前に、送信内容を目視で確認したい場面は多いはずです。
Nodemailerは nodemailer.createTestAccount() で使い捨てのSMTPアカウントを
その場で発行できます。実際の受信箱にはメールを届けず、送信結果に含まれる
プレビューURLをブラウザで開くだけで、件名・本文・添付ファイルまで確認できます。
import nodemailer from "nodemailer";
const testAccount = await nodemailer.createTestAccount();
const transporter = nodemailer.createTransport({
host: testAccount.smtp.host,
port: testAccount.smtp.port,
secure: testAccount.smtp.secure,
auth: {
user: testAccount.user,
pass: testAccount.pass,
},
});
const info = await transporter.sendMail({
from: '"開発用" <dev@example.com>',
to: "test@example.com",
subject: "テスト送信",
text: "これはEtherealへのテスト送信です。",
});
// メール本文をブラウザで確認できるURL
console.log("プレビューURL:", nodemailer.getTestMessageUrl(info));
CI環境や開発中の動作確認で、実際のユーザーにメールが届いてしまう事故を防ぎながら 送信ロジックをテストできるのがEtherealの利点です。
添付ファイルと埋め込み画像つきのHTMLメールを送る
請求書PDFの送付や、本文中にロゴ画像を埋め込みたいメールでは、attachments に
配列でファイル情報を渡します。cid を指定した添付ファイルは、HTML本文の
<img src="cid:..."> から参照できる埋め込み画像になります。
await transporter.sendMail({
from: '"請求担当" <billing@example.com>',
to: "user@example.com",
subject: "請求書のご案内",
html: '<p>請求書を添付します。</p><img src="cid:logo" />',
attachments: [
{
filename: "invoice.pdf",
path: "./files/invoice.pdf",
},
{
filename: "logo.png",
path: "./assets/logo.png",
cid: "logo", // HTML側のcid:logoと対応
},
],
});
path にはローカルファイルパスだけでなく、URLやBufferも指定できるため、
生成したPDFをディスクに書き出さずそのまま添付する、といった使い方も可能です。
OAuth2認証でGmailからメールを送る
GmailやMicrosoft 365など、パスワード認証を廃止しOAuth2を必須とするサービスに
対しても、Nodemailerは auth.type: "OAuth2" を指定するだけで対応できます。
事前にGoogle Cloud ConsoleでクライアントIDとリフレッシュトークンを取得しておく
必要がありますが、送信自体のコードは通常のSMTP送信とほぼ変わりません。
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: "your-address@gmail.com",
clientId: process.env.GMAIL_CLIENT_ID,
clientSecret: process.env.GMAIL_CLIENT_SECRET,
refreshToken: process.env.GMAIL_REFRESH_TOKEN,
},
});
await transporter.sendMail({
from: "your-address@gmail.com",
to: "user@example.com",
subject: "OAuth2経由の送信テスト",
text: "OAuth2認証でメールを送信しました。",
});
アプリパスワードのような簡易認証に頼らずに済むため、Googleアカウント側の セキュリティポリシーが厳しい組織でも運用しやすくなります。
コネクションプーリングで大量送信を効率化する
メルマガや一括通知のように、短時間で多数のメールを送る場合は、送信のたびに
SMTP接続を張り直すとオーバーヘッドが無視できません。pool: true を指定すると、
Nodemailerが内部でコネクションを再利用し、maxConnections や maxMessages で
同時接続数や1コネクションあたりの送信上限を制御できます。
const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
pool: true,
maxConnections: 5,
maxMessages: 100,
});
const recipients = ["a@example.com", "b@example.com", "c@example.com"];
await Promise.all(
recipients.map((to) =>
transporter.sendMail({
from: '"お知らせ" <news@example.com>',
to,
subject: "今週のアップデート",
text: "今週のアップデート内容をお届けします。",
})
)
);
transporter.close(); // 送信が終わったらプールを閉じる
送信先が数千件規模になる場合は、SMTPサーバー側のレート制限にも注意しながら
maxConnections を調整するとよいでしょう。
まとめ
Nodemailerは、SMTP・Amazon SES・sendmailといった送信経路の違いを createTransport()
の設定だけで吸収してくれるため、開発環境ではEtherealでプレビューし、本番では
実際のSMTPやSESに切り替える、という運用がコードをほとんど変えずに実現できます。
添付ファイルやOAuth2認証、コネクションプーリングまで標準機能でカバーしている
ので、追加のライブラリに頼らずメール送信まわりを一通り実装できるはずです。
まずは createTestAccount() を使ったEtherealでのテスト送信から試してみてください。
