メールヘッダを分析する

id:kizashi1122 です。

弊社はメールやチャットを一元的に管理し、チームで対応できるサービスである Re:lation を開発・提供しています。

メールは基本的には送ったらすぐに相手に届きます(正確には相手のサーバーに届く) 。 しかしなかなか届かない場合もあります。もともと非同期な仕組みではあるし、相手はメールを読み出して即時に返事を返すものでもないので、あまり気にならないと言えば気にならないです。

とは言え、サービスを提供する側としては、どこで遅延したのかは気になりますし、実際お客様からお問い合わせをいただくこともあります。
そこで、

  • Re:lation に届く前にすでに遅れていたのか?
  • それとも、Re:lation に届いたあと、データベースに取り込むまでの間に遅延したのか?

を切り分けます。前者であれば、その遅延は不可抗力と言えます。

さてどうやってそこを切り分けるのでしょうか。

Received ヘッダを見る

メールのソースを見てみると、ヘッダの中に Received というヘッダが複数あるのが確認できるかと思います。

Received: by 2002:a05:7208:b0c8:b0:9b:d29d:b1ed with SMTP id d8csp6293794rbb;
        Mon, 7 Apr 2025 00:08:10 -0700 (PDT)
Received: from ml43.willap.jp (ml43.willap.jp. [54.64.68.59])
        by mx.google.com with ESMTPS id 41be03b00d2f7-af9bc2c924csi10708441a12.81.2025.04.07.00.08.09
        for <me@example.com>
        (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
        Mon, 07 Apr 2025 00:08:10 -0700 (PDT)
Received: from unknown (unknown [172.31.8.103]) by willap.jp(2.18.0.0.7) with SMTP; Mon,07 Apr 2025 16:06:56 +0900 (JST)

何行もあるヘッダのうち、Received ヘッダを抜き出してみました。これは実際のヘッダです(キッザニア甲子園から私のGmail宛に送られたメールです)

Received ヘッダの読み方

Received ヘッダは下から順に読んでいきます。 メール送信ボタンを押してから、相手のサーバーに届くまで、複数のサーバが Received ヘッダを追加していってるわけです。

また、Received ヘッダはこのようなフォーマット担っています。

Received: from A by B; DATE

ここから読み取れるのは、

  • B サーバがDATE時間に、このヘッダを付与した
  • B サーバはAサーバからこのメールを受け取った

ということになります。DATE部分はメールサーバのタイムゾーンで表示される ことになるので、複数のタイムゾーンにまたがっていると時間の計算がちょっと難しいですね。

つまり、Re:lation に届くまでのサーバ間で遅延があれば不可抗力と言えるわけです。

しかし読み解くの大変ですよね。何か便利なものないかしら?

なんかサービスないのか?

実は無料で使えるサービスがあります。ヘッダ部分をテキストエリアに貼り付けるだけです。

なんと Google もToolbox として用意してくれています。しかしとても見にくい。
一方 MxToolbox は、グラフ化してくれてるのでわかりやすいです。

しかし、ヘッダ情報をペタっと貼って送るのは抵抗があります よね。貼り付け方によっては、メールアドレスやサブジェクトの情報も送ることになってしまいます。おそらく収集はしていないだろうとは思いますが、可能性は残り続けます。

作ろうかな

メールヘッダをパースする仕組みを作ろうかなと思いましたが、まずオープンソースで何かないかを探してみました。
ちゃんとグラフ化もされるし良さそうです。

github.com

これが見つかりました。READMEをみると、「Googleはすべてのホップ数を表示しない」とか「MxToolboxは正確でないし遅い」とあり、このあたりの課題感から作ったのだろうということがわかります。これはよい予感。

しかし古い(まあメールというテクノロジーが古いので処理の中身が変わらないということはあるのですが)

そこで

上記のレポジトリをフォークして、

  • docker-compose.yml の volume をいじって開発しやすいように
  • タイムゾーンは JST に合わせるように
  • mime encode されたままは気持ち悪いので、mime decode して表示
  • bootstrap3 を bootstrap4 に(5は諦めた)

の対応をしたものがこちらです。これをローカルで使ったり、自分でホスティングすればデータが意図せず流出することも防ぐことができます。

github.com

上述メールの例だとGoogle側で74秒の遅れがあったことがわかりました。

というわけで

自分で作らずに、すでにあるものをちょこちょこっと修正するだけでなんとかなりました。

やったね。