~fvknk/bk

技術関連の備忘録

メール送信の仕組みが覚えられないので手を動かしながら調べてみた

はじめに

SMTPが覚えられないため、実際に手を動かしながらまとめてみました。

SMTPとはなにか

まず、送信側のプロトコルであるSMTPの特徴をざっと書き出します。

  • Simple Mail Transfer Protocolの略
  • メールの送信・転送を行うためのプロトコル
  • TCPポートは25番

以上の情報はざっくりと頭に入ってはいるのですが、実際に何が行われているのかよくわかっていないため、詳細手順を追っていきます。

SMTPの詳細な手順

SMTPはクライアントとメールサーバ間でTCPコネクションを確立して、以下の手順でやり取りをするもののようです。

上記のクライアントからメールサーバーへのコマンドの送信を手元の端末で試してみました。

SMTPを使ってメールを送信してみる

1. Dockerコンテナを立てる

SMTPサーバーをたてることができるDockerイメージを探したところ、MailHogというものがあったためそちらを利用しました。

今回はMailHogの以下の機能を使って、SMTPを使ったメール送信の理解を進めていきます。

  • SMTP用のアプリケーションの構成
  • Web上でのメッセージの閲覧

MailHogでは、SMTP通信用のポートとして1025、HTTP用のポートとして8025を使うようなので、コンテナ起動のコマンドでポートの指定をしています。

$ docker run -p 1025:1025 -p 8025:8025 --name smtp_test --rm -d mailhog/mailhog
$ docker ps                       
CONTAINER ID   IMAGE                            COMMAND            CREATED             STATUS             PORTS                                            NAMES
2841e62b4a98   mailhog/mailhog                  "MailHog"          7 seconds ago       Up 6 seconds       0.0.0.0:1025->1025/tcp, 0.0.0.0:8025->8025/tcp   smtp_test

registry.hub.docker.com

ブラウザで http://localhost:8025 にアクセスしたところ、以下のような画面が表示されました。

2. コマンドを実行する

シーケンス図に沿ってコマンドを送信します。

ドメイン等はデフォルトのままなので、以下を見ながら指定しました。

github.com

$ telnet localhost 1025
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 mailhog.example ESMTP MailHog
EHLO mailhog.example
250-Hello mailhog.example
250-PIPELINING
250 AUTH PLAIN
MAIL FROM:<soshinsya@sender.com>
250 Sender soshinsya@sender.com ok
RCPT TO:<jushinsya@receiver.com>               
250 Recipient jushinsya@receiver.com ok
DATA
354 End data with <CR><LF>.<CR><LF>
Hello, World.
Goodbye, World.
.
250 Ok: queued as hrX_V8PWHuT8Vw9pEbb289G36P0caoNsLkPIQzKYsII=@mailhog.example
QUIT
221 Bye
Connection closed by foreign host.

http://localhost:8025 にアクセスすると、メッセージが1件増えていました。

開いてみると入力したテキストが表示されていました。送信成功のようです。Return-Pathには指定したMAIL FROMコマンドで指定したメールアドレスが表示されていますが、Receivedには、mailhog.exampleのドメインから送信されていることがわかります。

また、DATAコマンド送信後のメッセージはMIMEの仕様に沿っているようです。

www.rfc-editor.org

試しに本文のFromヘッダーでメールアドレスを指定して、かつ MAIL FROMコマンドで指定するメールアドレスを異なるものにしてメールを送信してみたところ、無事に送信できました。

$ telnet localhost 1025
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 mailhog.example ESMTP MailHog
EHLO mailhog.example
250-Hello mailhog.example
250-PIPELINING
250 AUTH PLAIN
MAIL FROM:<soshinsha@dummy.com>     
250 Sender soshinsha@dummy.com ok
RCPT TO:<jushinsya@receiver.com> 
250 Recipient jushinsya@receiver.com ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: soshinsha@sender.com
To: jushinsha@receiver.com

test message.
.
250 Ok: queued as h9b3OSBwY-FFGNFY_AxNwiMTdgmfKagffjAnfm8lO_w=@mailhog.example
QUIT
221 Bye
Connection closed by foreign host.

受信したメールを http://localhost:8025 で確認したところヘッダーを表示していない状態では、Fromには DATA コマンド実行後のメールヘッダに指定したメールアドレスが表示されました。

ヘッダーを開いたところ、Receivedには先ほどと同様 mailhog.exampleReturn-Pathには MAIL FROM コマンドで指定したメールアドレスが指定されていることを確認できました。

何の対策もしていない場合であれば、FromReturn-Pathの改ざんは簡単そうです。 Receivedは信頼できるのかは不明だったので調べてみたところ、 Receivedヘッダーは送信者ではなく中継するサービスで付与されるもののようでしたので、FromReturn-Path よりは信頼性の高い情報になるのかと思いました。

www.rfc-editor.org

まとめ

SMTPの仕組みについて詳細な手順に踏み込んで手を動かしながらまとめてみました。 実はPOP3の方もdovecotを使いながら手を動かしてみていたのですが力尽きたので、気が向いたら続きをやろうと思います。