emailjs、mailgun-js、nodemailer、sendgrid は、JavaScript アプリケーションからメールを送信するためのライブラリですが、通信プロトコルや動作環境、保守状況に大きな違いがあります。nodemailer は Node.js 環境で SMTP プロトコルを使用する標準的なライブラリです。emailjs も SMTP クライアントですが、ブラウザ環境での動作も技術的に可能です。一方、mailgun-js と sendgrid は、それぞれ Mailgun と SendGrid というメール配信サービスの API を利用するためのライブラリですが、現在はより新しい公式パッケージへの移行が推奨されています。フロントエンド開発者がこれらを選ぶ際は、サーバー側で動作させるか、クライアント側で動作させるか、そしてセキュリティリスクをどう管理するかが重要な判断基準になります。
JavaScript でメール機能を実装する際、emailjs、mailgun-js、nodemailer、sendgrid という 4 つのパッケージがよく候補に挙がります。しかし、これらは同じ「メール送信」でも、裏側の仕組みや適した場所が全く異なります。フロントエンドアーキテクトとして、これらを選定する際は「どこで動かすか(サーバーかブラウザか)」と「どう保守するか」の 2 点が最重要になります。ここでは、実装コードと保守状況を元に、技術的な違いを明確にします。
パッケージの導入方法は単純ですが、依存関係の管理において違いがあります。特に sendgrid と mailgun-js は、後述する通り古いパッケージであるため、インストール段階で将来の技術的負債を抱えるリスクがあります。
nodemailer
Node.js プロジェクトで標準的に使用されます。SMTP サーバーの設定をオブジェクトで渡して初期化します。
npm install nodemailer
// Node.js
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
secure: false,
auth: { user: 'user', pass: 'pass' }
});
emailjs
SMTP クライアントとして動作します。ブラウザでも Node.js でも動作しますが、設定には SMTP 認証情報が必要です。
npm install emailjs
// Browser or Node.js
const emailjs = require("emailjs/email");
const server = emailjs.server.connect({
user: "username",
password: "password",
host: "smtp.emailjs.com",
ssl: true
});
mailgun-js
Mailgun の API を使うためのラッパーです。API キーとドメインが必要です。
npm install mailgun-js
// Node.js
const mailgun = require('mailgun-js')({
apiKey: 'key-yourapikey',
domain: 'yourdomain.com'
});
sendgrid
SendGrid の API を使うための古いラッパーです。API キーが必要です。
npm install sendgrid
// Node.js
const sendgrid = require('sendgrid')('YOUR_API_KEY');
実際の送信コードを見ると、プロトコルの違い(SMTP か HTTP API か)がはっきりとわかります。SMTP はメールサーバーとの直接通信、API は配信サービス経由の通信です。
nodemailer
SMTP プロトコルを使用します。sendMail メソッドで送信します。サーバー側での使用が前提です。
await transporter.sendMail({
from: '"Me" <me@example.com>',
to: 'recipient@example.com',
subject: 'Hello',
text: 'World'
});
emailjs
これも SMTP プロトコルです。server.send メソッドを使用します。ブラウザで実行すると、認証情報がクライアント側に露出します。
server.send({
text: "email body",
from: "you@yourdomain.com",
to: "someone@otherdomain.com",
subject: "Test Email"
}, callback);
mailgun-js
HTTP API を使用します。messages().send で送信します。サービス側の機能(追跡など)が使えます。
const data = {
from: 'Excited User <me@samples.mailgun.org>',
to: 'test@example.com',
subject: 'Hello',
text: 'Testing some Mailgun awesomness!'
};
mailgun.messages().send(data, function (err, body) { /*...*/ });
sendgrid
HTTP API を使用します。send メソッドで送信します。ただし、この API は古いバージョンに基づいています。
const email = new sendgrid.Email({
to: 'test@example.com',
from: 'test@test.com',
subject: 'Hello',
text: 'World'
});
sendgrid.send(email, function(err, json) { /*...*/ });
これが最も重要な architectural decision(アーキテクチャの決定)ポイントです。フロントエンド開発者がクライアントサイドのコードにこれらのライブラリを直接含めることは、多くの場合セキュリティ上の問題を引き起こします。
nodemailer と emailjs のリスク
これらは SMTP 認証情報(ユーザー名とパスワード)を必要とします。これをフロントエンドのコードに書くと、誰でもあなたのメールサーバーにログインできるようになってしまいます。そのため、nodemailer は必ずサーバー側(Node.js バックエンド)で動かす必要があります。emailjs も同様ですが、サービス提供元の EmailJS 社が提供する @emailjs/browser という別の SDK があり、こちらは認証情報を隠蔽できる仕組みになっているため、フロントエンドから使うならこちらを選ぶべきです。
mailgun-js と sendgrid の現状
これらは API キーを使用するため、SMTP パスワードよりはマシですが、やはりクライアント側に置くべきではありません。さらに重要なのは、これらのパッケージ名自体が「レガシー(旧世代)」であるという点です。
mailgun-js は保守がほぼ停止しており、公式は mailgun.js への移行を案内しています。sendgrid パッケージは非推奨であり、公式は @sendgrid/mail への移行を強く推奨しています。新しいプロジェクトで mailgun-js や sendgrid を選ぶことは、将来のアップデートやセキュリティ修正を受けられなくなることを意味します — これは技術的負債になります。
| 特徴 | nodemailer | emailjs | mailgun-js | sendgrid |
|---|---|---|---|---|
| プロトコル | SMTP | SMTP | HTTP API | HTTP API |
| 主な環境 | サーバー (Node.js) | サーバー / ブラウザ | サーバー (Node.js) | サーバー (Node.js) |
| 認証情報 | ユーザー/パスワード | ユーザー/パスワード | API キー | API キー |
| 保守状況 | ✅ 活発 | ✅ 活発 | ⚠️ 停滞 (移行推奨) | ❌ 非推奨 (移行必須) |
| フロントエンド | ❌ 非推奨 | ⚠️ リスクあり | ❌ 非推奨 | ❌ 非推奨 |
プロフェッショナルな開発現場では、以下の基準で選定を行います。
nodemailer が唯一の正解です。安定しており、機能も豊富です。emailjs パッケージは使わないでください。代わりに、EmailJS 社の @emailjs/browser SDK を使用します。これなら認証情報を隠せます。mailgun-js ではなく mailgun.js を、sendgrid ではなく @sendgrid/mail を選んでください。メール送信はセキュリティと信頼性が最優先される機能です — 古いパッケージや、認証情報が漏れる実装は避け、最新の公式推奨構成を採用することが、結果的にメンテナンスコストを下げることにつながります。
SMTP プロトコルでメールを送信したい場合に選択しますが、ブラウザで使うと認証情報が漏れるリスクがあるため注意が必要です。信頼できるサーバー環境内での使用に適しています。フロントエンドから直接送る場合は、セキュリティを強化した公式の @emailjs/browser SDK の検討を強く推奨します。
Mailgun サービスを利用したい場合ですが、このパッケージは保守が停滞しているため、新しいプロジェクトでは使用しないでください。代わりに、公式が提供する最新の mailgun.js を使用して、セキュリティと機能のサポートを受けるべきです。
Node.js サーバー内で SMTP を使ってメールを送りたい場合に選択します。独自の SMTP サーバーや、Gmail などの既存プロバイダーと直接接続する際に最適です。サーバー側の実装において、最も信頼性が高く柔軟な選択肢となります。
SendGrid サービスを利用したい場合ですが、このパッケージは非推奨です。新しいプロジェクトでは、公式の @sendgrid/mail を使用してください。これにより、最新の API 機能とセキュリティアップデートを利用できます。
Send emails with ease!
This library lets you send rich HTML emails, attachments (from files, streams, or strings), and plain text messages to any SMTP server.
PLAIN, LOGIN, CRAM-MD5, and XOAUTH2.It's super simple!
npm install emailjs
Here's how easy it is to send emails:
import { SMTPClient } from 'emailjs';
const client = new SMTPClient({
user: 'your-username',
password: 'your-password',
host: 'smtp.your-email.com',
ssl: true, // Use SSL for secure connection
});
async function sendMyEmail() {
try {
const message = await client.sendAsync({
text: 'Hello from emailjs! This is a test message.',
from: 'You <your-email@example.com>',
to: 'Someone <someone@example.com>',
subject: 'Exciting News from emailjs! 🎉',
});
console.log('Email sent successfully:', message);
} catch (err) {
console.error('Failed to send email:', err);
} finally {
client.smtp.close(); // Don't forget to close the connection!
}
}
sendMyEmail();
import { SMTPClient, Message } from 'emailjs';
const client = new SMTPClient({
user: 'your-username',
password: 'your-password',
host: 'smtp.your-email.com',
tls: true,
});
async function sendRichEmail() {
const htmlContent = `
<h1>Greetings!</h1>
<p>This is an <b>HTML email</b> with a lovely picture and an attachment.</p>
<img src="https://raw.githubusercontent.com/eleith/emailjs/HEAD/cid:my-image" alt="Embedded Image" width="150" height="100">
<p>Check out the attached file!</p>
`;
const message = new Message({
from: 'You <your-email@example.com>',
to: 'Someone <someone@example.com>',
subject: 'Your Awesome HTML Email! 🖼️📄',
attachment: [
{
data: htmlContent,
alternative: true, // This part is the HTML body
contentType: 'text/html',
},
{
path: 'path/to/your/document.pdf', // Attach a file from disk
type: 'application/pdf',
name: 'document.pdf',
},
{
path: 'path/to/your/image.jpg', // Embed an image for the HTML
type: 'image/jpeg',
name: 'cool_image.jpg',
// Reference in HTML with cid:my-image
headers: { 'Content-ID': '<my-image>' },
},
],
});
try {
await client.sendAsync(message);
console.log('Rich email sent successfully!');
} catch (err) {
console.error('Failed to send rich email:', err);
} finally {
client.smtp.close();
}
}
sendRichEmail();
The emailjs library is fully typed, here is a brief overview of most likely to
be used methods
new SMTPClient(options)Create a new client instance to connect to your SMTP server.
const options = {
user: 'your-username', // 🔑 Username for logging into SMTP
password: 'your-password', // 🤫 Password for logging into SMTP
host: 'smtp.your-email.com', // 🌐 SMTP server host (defaults to 'localhost')
port: 587, // 🔌 SMTP port (defaults: 25 unencrypted, 465 SSL, 587 TLS)
ssl: true, // 🔒 Boolean or object for immediate SSL connection
tls: true, // 🔐 Boolean or object (see typescript types) to initiate STARTTLS
timeout: 5000, // ⏳ Max milliseconds to wait for SMTP responses
domain: 'your-domain.com', // 🏠 Domain to greet SMTP with (defaults to os.hostname)
authentication: ['PLAIN', 'LOGIN'], // 🤝 Preferred authentication methods
logger: console, // 📝 Override the built-in logger (e.g., custom logging)
};
SMTPClient#send(message, callback)Sends an email message. You can pass a Message instance or a headers object.
client.send(messageObject, (err, details) => {
if (err) console.error(err);
else console.log('Message sent:', details);
});
SMTPClient#sendAsync(message)a promise-based way to send emails! ✨
try {
const details = await client.sendAsync(messageObject);
console.log('Message sent:', details);
} catch (err) {
console.error('Failed to send:', err);
}
new Message(headers)Constructs an RFC2822-compliant message object.
const headers = {
from: 'sender@example.com', // 💌 Sender (required!)
to: 'recipient@example.com', // 📬 Recipients (at least one of to, cc, or bcc)
cc: 'carbon-copy@example.com', // 👥 CC recipients
bcc: 'blind-copy@example.com', // 🕵️♀️ BCC recipients
subject: 'Your Subject Here', // 📝 Email subject
text: 'Plain text body.', // 🗒️ Plain text content
attachment: [{ data: 'Hello!' }], // 📎 One or more attachments
};
Message#attach(options)Adds an attachment to the message. Can be called multiple times.
message.attach({
path: 'path/to/file.zip', // 📁 Path to a file on disk
data: 'Binary content as string or buffer', // 📄 Raw data
stream: fs.createReadStream('file.jpg'), // 🌊 A readable stream
type: 'application/zip', // MIME type
name: 'custom-name.zip', // Filename perceived by recipient
alternative: true, // attach inline as an alternative (e.g., HTML body)
inline: true, // If true, attached inline (e.g., for <img src="https://raw.githubusercontent.com/eleith/emailjs/HEAD/cid:...">)
headers: { 'X-Custom-Header': 'value' }, // Custom attachment headers
});
Message#checkValidity()Synchronously validates that a Message is properly formed before sending.
const { isValid, validationError } = message.checkValidity();
if (!isValid) {
console.error('Message is invalid:', validationError);
}
# Run all tests
npm test
# Run tests with code coverage report
npm run test:coverage
for a local smtp testing experience, use our Mailpit compose service
Ensure you have Docker and Docker Compose installed.
# From the project root, start Mailpit
docker compose up
Mailpit will be accessible via:
http://localhost:8025localhost:1025You can use the provided scripts to send different types of emails to your local Mailpit instance.
First, make sure the emailjs library is built:
npm run build
Then, run any of the example scripts:
# Send a plain text email
node scripts/send-text.js
# Send an HTML email
node scripts/send-html.js
# Send an email with attachments
node scripts/send-attachment.js
After running a script, open your Mailpit Web UI (http://localhost:8025) to
see the emails stream in! 📩