node.jsの有名なメール送信ライブラリにNodemailerがあります。必要な機能がすべて揃っており、TypeScript環境にもストレスなく導入できて、動作に関してはPromiseを返してくれたり、非常に使いやすいライブラリです。

以下、導入方法や使い方についてです。

インストール

npm install nodemailerで導入完了です。TypeScript環境ではnpm install @types/nodemailer --save-devで型定義を別途インストールします。

設定

スマホやパソコンで独自ドメインのメールを使う時と同じ設定です。

  1. ホスト名(Host Name)
  2. メールアドレス(User Name)
  3. パスワード(Password)

の3つの情報を使ってメールを送信します。これらの情報はメールアドレスの設定をしたサービス(レンタルサーバーなど)の管理画面で確認できます。

import { createTransport } from "nodemailer";

const transporter = createTransport({
  host: "mail.example.com", // ホスト名
  port: 465,
  secure: true,
  auth: {
    user: mail@example.com, // メールアドレス
    pass: ******** // パスワード
  }
});

注意点として、Githubなどにパスワードをそのままアップロードすることになるので、セキュリティー上の理由から以下のように環境変数をご活用ください。プライベートなリポジトリだとしてもです。

import { createTransport } from "nodemailer";

const transporter = createTransport({
  host: "mail.example.com",
  port: 465,
  secure: true,
  auth: {
    user: process.env.MAIL_AUTH_USER, // 環境変数
    pass: process.env.MAIL_AUTH_PASS // 環境変数
  }
});

メールを送信する

送信の関数はsendMailになり、Promiseが返ってきます。送信の成功と失敗とで処理を分けたい時はTryCatchが使えます。

sendMail関数に必要なオプションは以下の通りです。

  • from(送信元)
  • to(送信先)
  • subject(件名)
  • text(メール内容)

その他のオプションには、メール受信後の送信先を指定するreplyTo、添付ファイルを複数送信できるattachments、HTML形式の本文で送れるhtmlなどがあります。

サンプルコードは以下の通りです。

try {
  await transporter.sendMail({
    from: `"Shinobi Works" <no-reply@example.com>`,
    to: `administer@example.com`,
    subject: "問い合わせがありました",
    text: `サイトにお問い合わせがありました...(略)`
  });
} catch (error) {
  console.log(`メールを送信できませんでした`);
  throw error;
}

注意点として、TryCatchでのエラーはホスト名やパスワードなどの情報に不備があってメール送信ができなかった場合のみキャッチされるため、toオプション(送信先メールアドレス)が間違っていたとしても成功になります。これはPHPのmail関数と同じで、送信先が正しいかどうかは別問題になるからです。

これはfromオプションにも言えるため、設定に使ったメールアドレスとfromのメールアドレスが一致しなくても送信できます。例えば、administer@example.comの情報でメール送信するとしても、fromオプションにno-reply@example.comを指定できます。システムでの自動返信メールに役立つかもしれません。

メールが送れない場合

APIと同じく、国外IPを制限しているレンタルサーバーがあるので、Netlifyなどの国外サーバーから実行する場合は制限を解除しなければなりません。私が試した時は502エラーが返ってきました。

全体コード

import { createTransport } from "nodemailer";

const transporter = createTransport({
  host: "mail.example.com",
  port: 465,
  secure: true,
  auth: {
    user: process.env.MAIL_AUTH_USER, // 環境変数
    pass: process.env.MAIL_AUTH_PASS // 環境変数
  }
});

try {
  await transporter.sendMail({
    from: `"Shinobi Works" <no-reply@example.com>`,
    to: `administer@example.com`,
    subject: "問い合わせがありました",
    text: `サイトにお問い合わせがありました...(略)`
  });
} catch (error) {
  console.log(`メールを送信できませんでした`);
  throw error;
}