メールアドレスを公開せずに受け付ける

個人サイトに問い合わせ先を置くとき、メールアドレスをページへ直接書けば簡単ですが、公開アドレスを避けたい場合は別の入口が必要です。一方、画面上に送信フォームを置くだけでは、入力をどこへ届けるか、送信に失敗したときに何を表示するかが決まりません。

このサイトでは、利用者が問い合わせフォームへ入力し、サーバーが固定の宛先へメールを送る構成にしています。送信元と宛先はサーバー設定で決まり、訪問者が入力するメールアドレスは返信先として扱います。

受信方法を選ぶ

表は横にスクロールできます。

方法よい点考えること
メールアドレスをページに掲載実装が不要で、通常のメールアプリから連絡できる公開アドレスを避けたい要件に合わない
外部フォームサービス送信・受信の仕組みを任せられるアカウント、利用条件、データの扱いを確認する
サイトと同じoriginの小さなAPI入力項目、検証、宛先をサイト側で管理できるSMTP設定、運用監視、迷惑送信対策が必要

今回は、サイト側で送信先を固定し、ブラウザからの送信元をOrigin・Hostヘッダーで確認するAPI方式を選びました。外部フォームの提供条件に合わせる必要がなく、送信項目と失敗時の返答を一つの実装で管理できます。その代わり、メール配信設定を安全に用意し、サーバーを運用する責任が残ります。

宛先をサーバー側で固定する

フォームから送れるのは、名前、返信先、問い合わせ区分、記事URL、本文、同意状態と迷惑送信対策用の項目です。宛先や差出人をリクエスト本文から受け取らないため、利用者が宛先を差し替える作りにはしていません。サーバーはメール本文を組み立て、固定の宛先へ送信し、入力されたメールアドレスだけをReply-Toに設定します。

送信前には同一origin、JSON形式、リクエストサイズ、各項目の型と長さ、区分、同意、記事URLのHTTP/HTTPS、隠し項目を検証します。HTTPヘッダー注入につながる改行も拒否します。接続元IPごとの回数制限と全体上限を設け、信頼設定のない X-Forwarded-For は接続元判定に使いません。

本番SMTPの接続情報は環境設定から読み込み、設定が不足または不正ならサーバーを起動しません。SMTPはTLSを必須にし、認証情報や本文をログへ出さない設定です。プレビュー用サーバーのAPIは送信せず、送信要求に503を返します。

成功・失敗を分けて扱う

メール送信関数がエラーを返す、または固定した宛先への受け付けが確認できない場合、APIは失敗を返します。フォーム側は失敗時に入力を残し、成功時だけ完了表示と入力クリアを行います。サーバーのSMTPエラー詳細や送信本文は利用者へのエラー応答へ含めません。

再現用の4ファイルはメール送信部分をモックに差し替え、固定の宛先・差出人とReply-Toの組み立てを検査できるようにしています。宛先と返信先の役割は次のとおりです。

宛先(To): サーバー設定で固定
差出人(From): サーバー設定で固定
返信先(Reply-To): フォーム入力のメールアドレス
  1. 4ファイルを指定の配置で保存する

    package.jsoncontact-service.mjsserver.mjsを同じフォルダへ置き、テストファイルをその中の tests フォルダに置きます。

  2. 依存パッケージを用意する

    Node.js 24を用意し、サンプルのルートフォルダで npm install を実行します。送信ライブラリの版は固定されていますが、テストはSMTPへ接続しません。

  3. テストを実行する

    同じフォルダで npm test を実行します。テストは送信先・差出人・Reply-To、入力拒否、送信失敗、プレビュー送信無効を検査します。テスト用の一時HTTPサーバーとモック送信関数を使います。

実行して確かめた応答

配布用ファイルの10テストは、Node.js v24.19.0とNodemailer 10.0.8で成功しました。主な結果を抜き出すと次のとおりです。

表は横にスクロールできます。

試した条件結果
正しい入力・固定宛先への受理をモックが返す200。Reply-Toに入力アドレスを設定
入力に宛先変更用のtoフィールドを追加422。送信しない
別originからのリクエスト403。送信しない
同じ接続元から連続して6回送信6回目は429
送信関数の失敗・別宛先だけの受理502。成功とは表示しない
プレビューの問い合わせAPI503。送信しない

モック検証の範囲

モックテストで確かめられるのは、サーバーがメール送信関数へどんな値を渡すか、入力をどの条件で拒否するか、送信結果に応じてどのHTTP応答を返すかです。SMTPサービスが実際にメールを受理し、受信箱へ到着することはこのテストでは検証できません。実メールの到着確認は別の運用確認です。

Originの確認はブラウザからの意図しない送信を抑える仕組みで、送信者の本人確認ではありません。ヘッダーを指定できるクライアントからの送信まで防ぐものではなく、回数制限や運用上の監視も必要です。

小さな単一プロセスのインメモリ制限は、複数インスタンス間で回数を共有しません。プロセスを再起動すると記録も初期化されます。負荷分散や複数台運用へ広げるなら、共有ストアを使うレート制限へ変更する必要があります。プロキシ配下では実際の接続経路を確認し、信頼できる単一プロキシのIPを明示した場合だけ転送IPを扱います。

問い合わせの運用では、メールに不要な個人情報や添付ファイルを含めないよう案内し、受信後に内容を確認して対応します。

実装とテスト

  • contact-service.mjs — origin・JSON・長さ・同意・URL・レート制限の検証と送信結果に応じた応答。
  • server.mjs — 必須設定の読み込み、TLS付きSMTP transporter、固定From/Toと入力Reply-Toの組み立て。
  • tests/contact-service.test.mjs — モック送信を使ったAPI・送信設定・失敗・プレビューのテスト。

テストの送信先はテスト用アドレスで、送信関数はモックです。実運用のSMTP到着確認とは分けて読んでください。