· 郵便局長 郵便局長

転送メールの「受け渡し記録」―ARC認証で信頼をつなぐ仕組み―

ARC(認証済み受け渡しチェーン)は、メール転送時の「受け渡し記録」です。各中継地点が署名を残すことで、最終的な受信者が経路を検証できます。


The ARC of Communication by KaiMail

郵便局で書留を扱うとき、私たちは必ず「受け渡し記録票」に判を押していました。差出人と受取人だけでなく、途中で荷物に触れたすべての担当者が記録に残す。配達区の担当が、集配センターが、そして最終的に配達した局員が。荷物が遠くから旅をしてきたとき、その票を見れば「誰がどこで受け取り、誰がどこへ渡したか」が一目でわかる仕組みでした。

メールの認証も、転送というひと手間が加わると、まったく同じ問題に直面します。そしてその問題を解決するために生まれたのが、ARC(Authenticated Received Chain)です。


ARCが生まれるまでの経緯

ARCを理解するには、まずメール認証の歴史を少し振り返る必要があります。

2012年前後、DMARC(Domain-based Message Authentication, Reporting & Conformance)が普及し始めました。DMARCは、送信元ドメインのDKIM署名とSPFレコードを照合することで、なりすましメールを検出する優れた仕組みです。企業や大手サービスがDMARCを導入するにつれ、迷惑メール対策は大きく前進しました。

しかし、ここで見落とされていた問題が浮かび上がりました。メール転送です。

日本でも、企業のシステム担当者が「会社のメールをGmailに転送して外出先でも読めるようにしたい」と設定したり、Mailman(メーリングリストソフトウェア)を使ったオープンソースコミュニティのMLがメンバー全員にメールを配信したりすることは日常的な光景です。こうした転送が行われると、転送元サーバーのIPアドレスは送信元ドメインのSPFレコードに載っていませんし、転送時にメール本文や件名が少し変わると、DKIMの電子署名も壊れてしまいます。

受信サーバーは難しい判断を迫られることになりました。「SPF・DKIMが通らないから拒否する」と設定すれば正規の転送メールが届かなくなる。「多少失敗しても受け入れる」と設定すれば迷惑メールが紛れ込む。どちらも困ります。

この課題を受けて、Google・Microsoft・Yahoo・LinkedInなどのエンジニアたちがARC作業部会を結成し、2015年頃から本格的な仕様策定を開始しました。実運用テストを繰り返しながら仕様を磨き、2019年7月にRFC 8617として正式に標準化されました。同年、GoogleがGmailでのARC対応を開始し、MicrosoftもExchange OnlineでARC署名の付与と検証をサポートしました。現在では、KaiMailのようなメール転送サービスにとって、ARCの実装は標準的なベストプラクティスとなっています。


転送メールの「受け渡し記録」―ARCの仕組み―

ARC は、転送経路上の各中継地点(フォワーダー)が3種類のヘッダーを付け加えることで機能します。書留の受け渡し記録票に「受け取った日時・担当者・状態」を記録するのと、まったく同じ発想です。

3種類のARCヘッダー:

ARC-Authentication-Results(AAR) ―「私がこのメールを受け取ったとき、認証結果はこうでした」という記録。SPF・DKIM・DMARCの検査結果を記します。転送のたびにi=1i=2と番号が増えていきます。

ARC-Message-Signature(AMS) ―「私がこのメールを受け取ったときの状態」に対する電子署名。DKIMと同じRSA暗号方式を使い、この時点でのメッセージが改ざんされていないことを証明します。

ARC-Seal(AS) ―「これより前に付けられたすべてのARCヘッダーセットを封印する」署名。チェーン全体を保護し、過去のスタンプが誰かに書き換えられていないことを保証します。

KaiMailが転送処理を行うと、受信したメールに以下のようなヘッダーが追加されます(読みやすくするために一部省略しています)。

ARC-Authentication-Results: i=1; kaimail.net;
  dkim=pass header.d=sender-domain.com;
  spf=pass smtp.mailfrom=sender-domain.com;
  dmarc=pass action=none header.from=sender-domain.com

ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed;
  d=kaimail.net; s=arc2024;
  h=from:to:subject:date:message-id:mime-version:content-type;
  bh=<ボディのハッシュ値>;
  b=<電子署名>

ARC-Seal: i=1; a=rsa-sha256; cv=none;
  d=kaimail.net; s=arc2024;
  b=<シール署名>

cv=(chain validation)という項目に注目してください。最初の転送地点(i=1)では常にcv=noneとなります。2つ目以降ではcv=pass(すべてのシールが検証済み)またはcv=fail(どこかで検証が失敗した)となります。

cv=failが必ずしも「不正なメール」を意味するわけではありません。「ARCに対応していない中継サーバーがメールを転送した」「予期しない変更が加わった」など、無害な原因も多くあります。チェーンはどこで何が起きたかを示すだけで、正直な記録です。


ARCヘッダーを実際に見てみよう ―Pythonコード―

少し時間をかけて、コードで確認してみましょう。今回も一緒に歩んでいきます。

PythonでDKIMとARCを扱う標準的なライブラリはdkimpyauthheadersです。まずインストールしてください。

pip install dkimpy authheaders

ARCヘッダーを付与してメールを署名する

import authheaders

# 転送処理を行うサーバーとして、受信した生のメールメッセージを読み込む
with open("received_message.eml", "rb") as f:
    raw_message = f.read()

# 受信時のSPF・DKIM・DMARC検査結果(本番環境ではMTAが生成)
auth_results = (
    "i=1; kaimail.net; "
    "dkim=pass header.d=example.com; "
    "spf=pass smtp.mailfrom=example.com; "
    "dmarc=pass action=none header.from=example.com"
)

# ARC署名用の秘密鍵(RSA、PEM形式)
with open("arc_private_key.pem", "rb") as f:
    private_key = f.read()

# ARCヘッダーを付けてメッセージに署名する
signed_message = authheaders.sign_message(
    message=raw_message,
    authserv_id="kaimail.net",
    selector=b"arc2024",
    domain=b"kaimail.net",
    privkey=private_key,
    sig=b"ARC",
    auth_results=auth_results.encode()
)

print(signed_message.decode())

ARCチェーンを検証する

import authheaders

with open("forwarded_message.eml", "rb") as f:
    raw_message = f.read()

# verify_arc_chainはチェーン全体の検証結果と各ホップの詳細を返す
cv, results = authheaders.verify_arc_chain(raw_message)

print(f"ARCチェーン全体の状態: {cv}")
for r in results:
    print(f"  ホップ {r['instance']}: シール={r['seal']}, メッセージ署名={r['ams']}")

cv=passが返れば、チェーン全体が正常に検証されています。転送によってSPFやDKIMが壊れていても、受信サーバーはこの結果をもとに信頼の判断を行うことができます。

ARCヘッダーをシンプルにパースする

import re
from email import message_from_bytes

with open("forwarded_message.eml", "rb") as f:
    msg = message_from_bytes(f.read())

arc_headers = {
    "ARC-Authentication-Results": [],
    "ARC-Message-Signature": [],
    "ARC-Seal": [],
}

for header_name in arc_headers:
    values = msg.get_all(header_name, [])
    for v in values:
        instance_match = re.search(r'i=(\d+)', v)
        instance = int(instance_match.group(1)) if instance_match else 0
        arc_headers[header_name].append((instance, v.strip()))

# インスタンス番号順に出力
for header_name, entries in arc_headers.items():
    for i, val in sorted(entries):
        print(f"\n[{header_name}] i={i}")
        print(val[:200], "..." if len(val) > 200 else "")

Google Admin Toolbox - ARC & Email Authentication

KaiMailのARC署名が正しいかどうかを確認する方法

KaiMail経由で届いたメールのARCヘッダーが適切かどうかを検証する方法をいくつかご紹介します。

方法1 ―Gmailの「元のメールを表示」機能―(コード不要)

  1. KaiMail経由で届いたメールをGmailで開く
  2. 右上の「…」メニューから 「元のメールを表示」 を選択する
  3. 「クリップボードにコピー」してから、Googleが提供するメッセージヘッダー解析ツール toolbox.googleapps.com/apps/messageheader/ に貼り付ける
  4. ARC-Sealcv=noneまたはcv=passを確認する

方法2 ―MXToolboxによるヘッダー解析―

MXToolboxの EmailHeaders解析ページ に生のヘッダーを貼り付けると、ARCヘッダーの形式や署名の状態を確認できます。

方法3 ―Pythonによる検証スクリプト―

Gmailで「元のメールを表示」→「元のメールをダウンロード」で.emlファイルとして保存し、以下のスクリプトで検証します。

import authheaders
import sys

eml_path = sys.argv[1]  # 例: python verify_arc.py my_message.eml

with open(eml_path, "rb") as f:
    raw = f.read()

cv, results = authheaders.verify_arc_chain(raw)

print(f"\n=== ARC チェーン検証結果 ===")
print(f"チェーン全体の状態: {cv.upper()}")
print()

for r in results:
    i = r.get("instance", "?")
    seal_status = r.get("seal", "不明")
    ams_status = r.get("ams", "不明")
    domain = r.get("domain", "不明")
    print(f"  ホップ {i} ({domain}):")
    print(f"    ARC-Seal:              {seal_status}")
    print(f"    ARC-Message-Signature: {ams_status}")

KaiMailで正常に転送されたメールの期待される出力:

=== ARC チェーン検証結果 ===
チェーン全体の状態: PASS

  ホップ 1 (kaimail.net):
    ARC-Seal:              pass
    ARC-Message-Signature: pass

方法4 ―OpenARCコマンドラインツール―

Linuxマシンをお使いの方は、openarcツールでも検証できます。

# インストール(Debian/Ubuntu系)
sudo apt install openarc

# 保存したメールファイルを検証
openarc -v -f forwarded_message.eml

ARC verification results: passが表示されれば正常です。

検証が失敗した場合

cv=failが表示された場合、最も多い原因はKaiMailの下流で別の転送処理が行われた際にARCチェーンが更新されなかったか、メッセージが何らかのフィルターによって変更された場合です。チェーンはどこで問題が発生したかを記録しているので、ログをさかのぼれば原因が特定できます。


なぜKaiMailはARCを実装しているのか

KaiMailは、メールの送信元と最終受信者の「あいだ」に位置するサービスです。まさにSPF・DKIMが最も壊れやすい位置です。ARCヘッダーを付与することで、KaiMailは最終受信サーバーに対してこう伝えています。「このメールを私が受け取ったとき、認証はこの状態でした。私の判断を信頼していただけますか。」

GmailやOutlookは、信頼済みのフォワーダーから届いたメールの判定に、ARCを考慮した仕組みを採用しています。転送されたメールが迷惑メールフォルダに入らずに受信トレイへ届くのは、こうした地道な実装の積み重ねによるものです。

さくらインターネットやXSERVERでメールアドレスを運用しながら、それをGmailやiCloudに転送して使っている方は多くいらっしゃいます。そういった場面でも、ARCはメールの信頼性を守る重要な役割を担っています。


最後に

郵便の受け渡し記録は、不信感から生まれたものではありませんでした。荷物が大切に届いてほしいという、関わる全員の責任感から生まれた仕組みでした。ARCも同じです。各転送地点が「自分はこう受け取り、こう渡した」と記録に残す。それが積み重なって、受取人のもとに届いたとき、その手紙の旅が証明されます。

ヘッダーの中には、たくさんの誠実な仕事が刻まれています。ぜひゆっくり読んでみてください。