メールアドレスを公開せずに受け付ける
個人サイトに問い合わせ先を置くとき、メールアドレスをページへ直接書けば簡単ですが、公開アドレスを避けたい場合は別の入口が必要です。一方、画面上に送信フォームを置くだけでは、入力をどこへ届けるか、送信に失敗したときに何を表示するかが決まりません。
このサイトでは、利用者が問い合わせフォームへ入力し、サーバーが固定の宛先へメールを送る構成にしています。送信元と宛先はサーバー設定で決まり、訪問者が入力するメールアドレスは返信先として扱います。
受信方法を選ぶ
表は横にスクロールできます。
| 方法 | よい点 | 考えること |
|---|---|---|
| メールアドレスをページに掲載 | 実装が不要で、通常のメールアプリから連絡できる | 公開アドレスを避けたい要件に合わない |
| 外部フォームサービス | 送信・受信の仕組みを任せられる | アカウント、利用条件、データの扱いを確認する |
| サイトと同じ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): フォーム入力のメールアドレス
- 4ファイルを指定の配置で保存する
package.json、contact-service.mjs、server.mjsを同じフォルダへ置き、テストファイルをその中のtestsフォルダに置きます。 - 依存パッケージを用意する
Node.js 24を用意し、サンプルのルートフォルダで
npm installを実行します。送信ライブラリの版は固定されていますが、テストはSMTPへ接続しません。 - テストを実行する
同じフォルダで
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。成功とは表示しない |
| プレビューの問い合わせAPI | 503。送信しない |
モック検証の範囲
モックテストで確かめられるのは、サーバーがメール送信関数へどんな値を渡すか、入力をどの条件で拒否するか、送信結果に応じてどの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到着確認とは分けて読んでください。