MDA(Mail Delivery Agent)
概要
MDA(Mail Delivery Agent) は、受信側の MTA(Mail Transfer Agent)から受け取ったメールを、最終的にユーザーのメールボックスに格納するソフトウェアです。RFC 5598(2009年)がメールアーキテクチャにおける MDA の役割を定義しており、正式には「Message Delivery Agent」と呼ばれています。
メールが送信者から受信者に届くまでには、MUA(メールクライアント)、MSA(送信受付)、MTA(中継・転送)、MDA(格納)の 4 つのエージェントが連携します。MDA はこのチェーンの最終段階を担当し、メールをユーザーが読める状態にする役割を持ちます。代表的な MDA として、Dovecot、Procmail、Maildrop、Cyrus IMAP があります。
MDA はメールのフィルタリングやソート処理も担います。Sieve スクリプト(RFC 5228、2008年)を使ったルールベースの振り分け、スパムフィルターとの連携、転送処理などが MDA の責任範囲です。
仕組み
MDA は受信側 MTA からメールを受け取り、Maildir 等のメールボックスに格納し、Sieve スクリプトによるフィルタリングを適用します。
メール配送チェーンにおける MDA の位置
メールの配送フローにおいて、MDA は受信側の最後のエージェントとして動作します。
- 送信者の MUA がメールを作成し、MSA に渡す
- 送信側 MTA が宛先ドメインの MX レコードを参照し、受信側 MTA に SMTP で転送する
- 受信側 MTA が SPF・DKIM・DMARC の認証チェックを実行する
- MTA が認証を通過したメールを MDA に引き渡す
- MDA がメールをユーザーのメールボックスに格納する
MTA から MDA への引き渡しは、同一サーバー上で行われる場合と、LMTP(Local Mail Transfer Protocol、RFC 2033)を使って別サーバーに渡す場合があります。Postfix と Dovecot を組み合わせる構成では、LMTP 経由での引き渡しが一般的です。
メールボックス形式
MDA がメールを格納する形式は主に 2 つあります。
Maildir 形式は、1 通のメールを 1 つのファイルとして保存します。new/、cur/、tmp/ の 3 つのサブディレクトリを使い、新着メール、既読メール、書き込み中のメールを分離します。ファイルロックが不要でサーバークラッシュ時のデータ破損リスクが低く、現在の主流です。Dovecot、Courier、qmail がこの形式を採用しています。
mbox 形式は、1 つのメールボックスを 1 つのファイルに格納します。すべてのメールが連結されて書き込まれるため、ファイルロックが必要です。メールの量が増えるとパフォーマンスが低下し、ファイル破損のリスクもあります。歴史的な理由で一部の環境では残っていますが、新規構築で採用されることは少なくなっています。
Sieve によるメールフィルタリング
MDA は Sieve スクリプトを使って、メールの振り分けや自動処理を実行できます。Sieve は RFC 5228 で定義されたメールフィルタリング言語で、MDA 上で動作します。
require ["fileinto", "reject"];
# メーリングリストを専用フォルダに振り分け
if header :contains "List-Id" "dev-team.example.com" {
fileinto "Lists.dev-team";
}
# DMARC 認証に失敗したメールを拒否
if header :contains "Authentication-Results" "dmarc=fail" {
reject "DMARC authentication failed";
}
Sieve はサーバーサイドで動作するため、MUA(メールクライアント)がオフラインでもフィルタリングが適用されます。Dovecot は Pigeonhole プラグインで Sieve をサポートしています。
LMTP による MTA と MDA の連携
LMTP(Local Mail Transfer Protocol)は、RFC 2033(1996年)で定義された、MTA から MDA へメールを引き渡すためのプロトコルです。SMTP と似たコマンド体系を持ちますが、メールキューを持たない点が異なります。LMTP では宛先ごとに個別のステータスコードを返せるため、複数の宛先に対して「このユーザーは成功、このユーザーは失敗」という応答が可能です。
LHLO mail.example.com
250-mail.example.com
250 PIPELINING
MAIL FROM:<sender@example.net>
250 OK
RCPT TO:<user1@example.com>
250 OK
RCPT TO:<user2@example.com>
550 5.1.1 User unknown
DATA
354 OK
Subject: Test
...
.
250 OK
この例では、user1@example.com への配送は成功し、user2@example.com は存在しないためハードバウンスとなります。
設定例
Postfix を MTA、Dovecot を MDA として LMTP ソケット経由で連携させる構成を示します。
Postfix + Dovecot LMTP の構成
Postfix を MTA、Dovecot を MDA として使う構成で、LMTP を使ってメールを引き渡す設定例です。
Postfix 側の設定(/etc/postfix/main.cf)で、ローカル配送を Dovecot の LMTP に委譲します。
mailbox_transport = lmtp:unix:private/dovecot-lmtp
Dovecot 側の設定(/etc/dovecot/conf.d/20-lmtp.conf)で、LMTP サービスを有効にします。
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
Dovecot の LMTP ソケット設定(/etc/dovecot/conf.d/10-master.conf)です。
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
この構成では、Postfix が受信したメールを UNIX ソケット経由で Dovecot に渡し、Dovecot が Sieve フィルタを適用した後にメールボックスに格納します。
確認方法
MDA が正しく動作しているかは、LMTP 接続テストで確認できます。Dovecot の LMTP が UNIX ソケットで待ち受けている場合、socat コマンドでテストします。
socat - UNIX-CONNECT:/var/spool/postfix/private/dovecot-lmtp
TCP ソケットで待ち受けている場合は、telnet で接続します。
telnet localhost 24
220 レスポンスが返れば LMTP サービスは稼働しています。
メールが正しくメールボックスに格納されているかは、Maildir の場合ファイルシステムで直接確認できます。
ls ~/Maildir/new/
新着メールがファイルとして存在すれば、MDA が正常に配送しています。
MDA に到達する前の段階(MX レコードやメール認証の設定)に問題がある場合もあります。外部の視点からも確認したい場合は、Labee Dev Toolbox の DNS API を使うと、外部の視点から見た MX レコードの設定を確認できます。
curl "https://labee.dev/api/dns?domain=example.com&type=MX"
{
"success": true,
"data": {
"domain": "example.com",
"records": {
"MX": [
{ "priority": 10, "exchange": "mail1.example.com" },
{ "priority": 20, "exchange": "mail2.example.com" }
]
}
},
"error": null,
"meta": { "responseTime": 45 }
}
data.records.MX に MX レコードが返っていれば、外部からメールサーバーを発見できる状態です。MX レコードが null の場合、外部からのメールがそもそも MTA に到達せず、MDA まで届きません。
よくある問題
MDA のトラブルは、ディスク容量不足、Sieve スクリプトの構文エラー、LMTP ソケットの接続失敗に集中しています。
メールボックスのディスク容量が不足している
MDA がメールを格納しようとした際にディスク容量が不足していると、配送に失敗します。LMTP 経由の場合、Dovecot は SMTP 4xx(一時的エラー)を返し、MTA は再送を試みます。容量超過が解消されないまま再送期限を迎えると、バウンスメールが送信者に返ります。ディスク使用量の監視とクォータの適切な設定で予防します。
Sieve スクリプトの構文エラーでメールがフィルタされない
Sieve スクリプトに構文エラーがあると、Dovecot はスクリプトの適用をスキップしてデフォルトの配送(INBOX に格納)を行います。エラーはログに記録されますが、メール自体は失われません。スクリプトの変更後は sieve-test コマンドで構文を検証します。
sieve-test script.sieve message.eml
パーミッション設定の誤りで配送に失敗する
Maildir のディレクトリやファイルのパーミッションが不適切だと、MDA がメールを書き込めません。Dovecot の場合、メールボックスディレクトリの所有者がメールユーザーと一致している必要があります。SELinux や AppArmor が有効な環境では、セキュリティコンテキストの設定不足で書き込みが拒否されることもあります。ログに Permission denied が記録されていないか確認します。
MTA と MDA 間の LMTP 接続が切断される
Postfix と Dovecot を UNIX ソケットで接続している場合、ソケットファイルのパスや権限の不一致で接続に失敗することがあります。Postfix のログに connect to dovecot-lmtp: No such file or directory と記録される場合は、ソケットファイルのパスが Postfix と Dovecot で一致しているか確認します。chroot 環境で Postfix を動かしている場合は、chroot パス配下にソケットを配置する必要があります。