「複合機からのメールが届きません。PCからTest-NetConnectionで25番を試したら成功するんですが……」
メールのトラブルでは、どこまでが正常で、どこからがおかしいのかを切り分けることが大切です。そのためには、名前解決、TCPの疎通、SMTPの応答、TLS、認証を、下の層から順に手を動かして確かめます。
第9回では、LinuxとWindowsの両方で使えるコマンドを、層ごとに紹介します。第8回までに出てきた確認の方法も、ここでまとめて扱います。
下の層から順に確かめる

| 段 | 確かめること | Linux | Windows |
|---|---|---|---|
| ① | 名前解決(MX・SPF 等) | dig | Resolve-DnsName |
| ② | TCP の疎通 | nc -vz | Test-NetConnection |
| ③ | SMTP の応答 | nc・telnet | PowerShell の TcpClient |
| ④ | TLS と証明書 | openssl s_client | PowerShell の SslStream |
| ⑤ | 認証 | openssl s_client で AUTH | 同左 |
最初に失敗した段に、原因のある層があります。順番に確かめていきましょう。
① MX・SPF・DMARCを引く
$ dig example.jp MX +short
10 mail1.example.jp.
20 mail2.example.jp.
$ dig example.jp TXT +short | grep spf1
"v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com -all"
$ dig _dmarc.example.jp TXT +short
"v=DMARC1; p=quarantine; rua=mailto:dmarc-rua@example.jp"
$ dig s1._domainkey.example.jp TXT +short # DKIM(セレクターは DKIM-Signature の s=)
$ dig _mta-sts.example.jp TXT +short # MTA-STS(TLS-RPT は _smtp._tls)
PS> Resolve-DnsName example.jp -Type MX -DnsOnly | Select-Object NameExchange, Preference
PS> (Resolve-DnsName example.jp -Type TXT -DnsOnly).Strings | Where-Object { $_ -like 'v=spf1*' }
PS> (Resolve-DnsName _dmarc.example.jp -Type TXT -DnsOnly).Strings
- MXは優先度の値の小さい順に試される。MXが無いとA/AAAAへ送る。
MX 0 .(Null MX)は受け取らない宣言(連載「DNS入門」第6回) - SPFはドメイン名に1つ、DMARCは
_dmarc.、DKIMはセレクター._domainkey.、MTA-STSは_mta-sts.、TLS-RPTは_smtp._tls.の下のTXT(第4回〜第6回) - 社内DNSと外部DNSで答えが違う(スプリットホライズン)と、社外から見た答えと食い違う。外部のリゾルバーや権威DNSを、digの
@や-Serverで指定して比べる(連載「DNS入門」第8回) - DANEのTLSA(
_25._tcp.MXのホスト名)は、digで型にTLSAを指定して引く
② ポートの疎通を確かめる
$ nc -vz mail.example.jp 25
Connection to mail.example.jp (203.0.113.25) 25 port [tcp/smtp] succeeded!
$ nc -vz -w 5 mail.example.jp 587
nc: connect to mail.example.jp (203.0.113.25) port 587 (tcp) timed out: Operation now in progress
PS> Test-NetConnection mail.example.jp -Port 25
ComputerName : mail.example.jp
RemoteAddress : 203.0.113.25
RemotePort : 25
InterfaceAlias : Ethernet
SourceAddress : 192.0.2.101
TcpTestSucceeded : True
- まずTCPでつながるかだけを見る。つながらなければSMTP以前の問題(ファイアウォール・OP25B・サービス停止・名前解決)
- timed outは途中で落とされている(ファイアウォール・OP25Bに多い)、Connection refusedは相手に届いたが待ち受けていない(サービス停止・ポート違い)
- Test-NetConnectionはWindows標準。失敗すると警告と
TcpTestSucceeded : Falseが出る。SMTPの応答やTLSまでは見ない - 送信元となる機器・サーバーから試す。ファイアウォールやリレーの許可は送信元IPで決まるため、自分の端末で通っても機器からは通らないことがある
冒頭の「PCからは成功する」は、まさにこの落とし穴です。
③ 手でSMTPを話す(nc・telnet)
$ nc -C relay.example.jp 25 # -C で改行を CRLF にする(RHEL の ncat も -C)
220 relay.example.jp ESMTP Postfix
EHLO app01.example.jp
250-relay.example.jp
250-PIPELINING
250-SIZE 10240000
250-STARTTLS
(略)
250 CHUNKING
MAIL FROM:<alert@example.jp>
250 2.1.0 Ok
RCPT TO:<ops@example.jp>
250 2.1.5 Ok
QUIT
221 2.0.0 Bye
- FreeBSD 14 の
ncには-Cが無い。Postfix は改行が LF だけの行も既定で受け付けるので、nc <サーバー> 25のままで試せる(smtpd_forbid_bare_newline = rejectの場合を除く) - 機器と同じ送信元・宛先でMAIL FROM・RCPT TOを打てば、拒否の理由(Relay access denied、Sender address rejected等)がその場で分かる。RCPT TOまで確かめてQUITすれば、メールは送られない
- telnetでも同じ(
telnet relay.example.jp 25)。Windowsのtelnetクライアントは既定で無効で、使うにはWindowsの機能の追加(管理者権限)が要る。Windowsでは次のPowerShellの方法を勧める - STARTTLSのあとは暗号化されるので、nc・telnetでは続けられない。暗号化後はopensslを使う
- 公開のMTAや他組織のサーバーで試さない。自組織のサーバー、または許可を得た相手に限る
PowerShellでSMTPを話す(TcpClient)
$tcp = [System.Net.Sockets.TcpClient]::new('relay.example.jp', 25)
$st = $tcp.GetStream()
$r = [System.IO.StreamReader]::new($st)
$w = [System.IO.StreamWriter]::new($st); $w.NewLine = "`r`n"; $w.AutoFlush = $true
function Read-Reply { do { $l = $r.ReadLine(); "S: $l" } while ($l -match '^\d{3}-') }
function Send-Cmd($c) { "C: $c"; $w.WriteLine($c); Read-Reply }
Read-Reply
Send-Cmd 'EHLO pc01.example.jp'
Send-Cmd 'MAIL FROM:<alert@example.jp>'
Send-Cmd 'RCPT TO:<user@example.com>'
Send-Cmd 'QUIT'
$tcp.Dispose()
S: 220 relay.example.jp ESMTP Postfix
C: EHLO pc01.example.jp
S: 250-relay.example.jp
(略)
C: RCPT TO:<user@example.com>
S: 454 4.7.1 <user@example.com>: Relay access denied
C: QUIT
S: 221 2.0.0 Bye
- Windows PowerShell 5.1・PowerShell 7のどちらでも、追加のインストールなしで動く。.ps1の実行がポリシーで止められる場合は、コンソールに貼り付けて実行する。
S:がサーバーの応答、C:が送ったコマンド Read-Replyは、250-のように3桁の後ろがハイフンの行が続く限り読み、複数行の応答を最後まで受け取る- 例では、このPCのIPがリレーを許されていないため
454 4.7.1 … Relay access deniedになった(第8回)。機器のIPから試すと結果が変わる
④ openssl s_clientの出力の読み方
$ openssl s_client -starttls smtp -connect mail.example.jp:25 -crlf \
-name app01.example.jp -verify_hostname mail.example.jp -nocommands
(抜粋)
Certificate chain
0 s:CN=mail.example.jp
i:C=US, O=Let's Encrypt, CN=YR1
1 s:C=US, O=Let's Encrypt, CN=YR1
i:C=US, O=ISRG, CN=Root YR
2 s:C=US, O=ISRG, CN=Root YR
i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
Verification: OK
Verified peername: mail.example.jp
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
250 CHUNKING

-starttls smtpで、EHLOとSTARTTLSまでを自動で行う。EHLOの名前は-name(省略時はmail.example.com)。465番では-starttls smtpを外す。-crlfで改行をCRLFにする- Certificate chain:0がサーバー証明書、1以降がサーバーの送った中間証明書。各番号のi:が次の番号のs:とつながるかを見る。かつてのLet’s EncryptのDST Root CA X3は2021年に期限切れで、現在はYR1→Root YR→ISRG Root X1のような鎖になる(連載「証明書入門」第7回)
Verification: OKとVerified peername:が出れば、チェーンと名前の両方の検証に成功している。名前は-verify_hostnameを付けたときだけ検証する- 最後の
250 …はSTARTTLSの前のEHLOの応答の残りで、ここからEHLOを打ち直す - 対話中に
RCPT TOやQUITを打つと、行頭のR・Qがs_clientのコマンド(再ネゴシエーション・終了)と解釈される。-nocommandsを付けるか、小文字で打つ
WindowsでSTARTTLS後の証明書を見る(SslStream)
$tcp = [System.Net.Sockets.TcpClient]::new('mail.example.jp', 25)
$st = $tcp.GetStream(); $r = [System.IO.StreamReader]::new($st)
$w = [System.IO.StreamWriter]::new($st); $w.NewLine = "`r`n"; $w.AutoFlush = $true
function Read-Reply { do { $l = $r.ReadLine(); "S: $l" } while ($l -match '^\d{3}-') }
Read-Reply | Out-Null
$w.WriteLine('EHLO pc01.example.jp'); Read-Reply | Out-Null
$w.WriteLine('STARTTLS'); Read-Reply # S: 220 2.0.0 Ready to start TLS
$ssl = [System.Net.Security.SslStream]::new($st, $false)
$ssl.AuthenticateAsClient('mail.example.jp') # 検証(名前を含む)に失敗すると例外
$ssl.SslProtocol # Tls13
$c = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($ssl.RemoteCertificate)
$c | Format-List Subject, Issuer, NotAfter
$ssl.Dispose(); $tcp.Dispose()
Subject : CN=mail.example.jp
Issuer : CN=YR1, O=Let's Encrypt, C=US
NotAfter : 2026/11/25 14:33:41
- STARTTLSへの220を受け取ったら、同じストリームの上でSslStreamのTLSハンドシェイクを始める。opensslの
-starttls smtpと同じ動き - 検証に失敗すると
AuthenticateAsClientが例外を出す。中身だけを見たいときは、連載「証明書入門」第4回と同じ、検証を省く指定({ $true })を調べる目的に限って使う - Windowsの表示では、Issuerの並びがopensslと逆(CNが先)になる。PowerShell 7なら
$ssl.NegotiatedCipherSuiteで暗号スイートも分かる
⑤ AUTHを試す
$ printf '\0alert@example.jp\0dummy-pass' | base64 # AUTH PLAIN:\0 ID \0 パスワード
AGFsZXJ0QGV4YW1wbGUuanAAZHVtbXktcGFzcw==
PS> [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("`0alert@example.jp`0dummy-pass"))
AGFsZXJ0QGV4YW1wbGUuanAAZHVtbXktcGFzcw==
$ openssl s_client -starttls smtp -connect relay.example.jp:587 -crlf -quiet -name app01.example.jp
EHLO app01.example.jp
(略)
250-AUTH PLAIN LOGIN
(略)
AUTH PLAIN AGFsZXJ0QGV4YW1wbGUuanAAZHVtbXktcGFzcw==
235 2.7.0 Authentication successful
- AUTH PLAINは「
\0 ID \0 パスワード」をBase64にして送る。AUTH LOGINは334 VXNlcm5hbWU6(Username:)と334 UGFzc3dvcmQ6(Password:)に、IDとパスワードを1つずつBase64で返す(RFC 4954、第4回) - Base64は暗号ではない。ログやパケットキャプチャに残れば誰でも元に戻せる。必ずTLSの後で送り、試験には試験用のアカウントを使い、終わったらパスワードを変える
- コマンドの履歴(
~/.bash_history、PowerShellの履歴)にパスワードが残る。read -sやGet-Credentialで入力して変数から組み立て、履歴を消す - 失敗すると
535 5.7.8 Error: authentication failed(Postfix)や535 5.7.139 Authentication unsuccessful(Microsoft 365。テナントでSMTP AUTHが無効など)が返る
テストメールを送る:swaksとSend-MailMessage
$ swaks --server relay.example.jp --port 587 --tls \
--auth LOGIN --auth-user alert@example.jp \
--from alert@example.jp --to ops@example.jp \
--ehlo app01.example.jp --header "Subject: swaks test"
(抜粋)
<- 220 relay.example.jp ESMTP Postfix
-> STARTTLS
<- 220 2.0.0 Ready to start TLS
~> AUTH LOGIN
<~ 235 2.7.0 Authentication successful
~> MAIL FROM:<alert@example.jp>
<~ 250 2.1.0 Ok
- swaksはSMTPの試験用ツール(最新は20240103.0)。
--tls(STARTTLSが必須)、--tls-on-connect(465番)、--auth、--quit-after RCPT(RCPT TOまで試して送らない)など、手打ちの手順を1行にできる。->が送信、<-が受信、~付きはTLSの中のやり取り - パスワードは
--auth-passwordで渡さず、プロンプトで入力する(履歴に残さない) - WindowsのSend-MailMessageは、Microsoftが非推奨(obsolete)としている。SMTPサーバーとの安全な接続を保証できないためで、PowerShellに直接の後継は無い。Microsoftは、サードパーティのMailKit、Exchange OnlineならMicrosoft Graphの
Send-MgUserMailを案内している
疎通や拒否の理由を調べるだけなら、送らずに、TcpClientの方法でRCPT TOまで確かめれば足ります。
ヘッダーの解析(Receivedをたどる)
届いたメールからは、ヘッダーで経路をたどります(第3回)。
Authentication-Results: mx.example.com; spf=pass smtp.mailfrom=example.jp;
dkim=pass header.d=example.jp; dmarc=pass header.from=example.jp
Received: from mx.example.com (mx.example.com [198.51.100.25])
by mbox01.example.com with LMTP id 7fKp0Q; Sat, 26 Sep 2026 10:15:03 +0900 ← ③
Received: from relay.example.jp (relay.example.jp [203.0.113.30])
by mx.example.com (Postfix) with ESMTPS id 4ZbQ1x2Kp3z9
for <user@example.com>; Sat, 26 Sep 2026 10:15:02 +0900 (JST) ← ②
Received: from app01.example.jp (app01.example.jp [192.0.2.21])
by relay.example.jp (Postfix) with ESMTP id 8C1E0A1B2F
for <user@example.com>; Sat, 26 Sep 2026 10:15:01 +0900 (JST) ← ①

- 下から上へ読むと、最初のサーバーから受信箱までの経路になる。各行のfrom(送ってきた相手)と、1つ下の行のby(受け取ったサーバー)がつながっているかを見る
- 時刻の差がそのサーバー間の遅延。
with ESMTPSはTLSで受け取ったことを示す。idはそのサーバーのキューIDで、ログの追跡に使える - 自組織のサーバーが付けた行より下は、送信者が偽って書ける。判断は、自組織の受信サーバーの行とAuthentication-Resultsで行う
- 長いヘッダーは、MicrosoftのMessage Header Analyzer(解析はブラウザーの中で行う)やGoogle Admin ToolboxのMessageheaderに貼り付けると、経路と遅延を表で見られる。後者は入力をサーバーへ送るため、個人情報を含むヘッダーの扱いに注意する
ログの追跡(キューID・Message-ID)
# ① 利用者のヘッダーの Message-ID から、このサーバーのキューIDを探す
$ grep 'message-id=<20260926011501.4F2A@app01.example.jp>' /var/log/maillog
Sep 26 10:15:01 relay postfix/cleanup[2346]: 8C1E0A1B2F: message-id=<20260926011501.4F2A@app01.example.jp>
# ② キューIDで1通の全行を出す(第8回)
$ grep 8C1E0A1B2F /var/log/maillog
# ③ 相手のキューID(queued as …)を相手の管理者に伝える
… status=sent (250 2.0.0 Ok: queued as 4ZbQ1x2Kp3z9)
# Microsoft 365 の場合(Exchange Online PowerShell)
PS> Get-MessageTraceV2 -MessageId '<20260926011501.4F2A@app01.example.jp>'

- Message-IDは全経路で変わらない(送信側が付けた値。無ければ最初のMTAが付ける)。キューIDはサーバーごとに変わる。Message-IDで入口を見つけ、キューIDでそのサーバーの中を追う
- サーバーが複数台なら、時刻をそろえて(NTP・タイムゾーン)突き合わせる。ログはsyslogサーバーやSIEMに集めておく(連載「syslog入門」)
- Microsoft 365はメッセージ追跡(Exchange管理センター、または
Get-MessageTraceV2。旧Get-MessageTraceは2025年9月から廃止が進んでいる)、Google Workspaceは管理コンソールのメールログ検索で追う(第10回) - 相手側に調べてもらうときは、時刻(タイムゾーン付き)・送信者・宛先・Message-ID・相手のキューIDを伝える
考えてみよう
- WindowsのPCから
Test-NetConnection -Port 25は成功するのに、複合機からのメールは届きません。次に何を、どの順で確かめますか。 openssl s_client -starttls smtpでVerify return code: 21 (unable to verify the first certificate)が出ました。何が原因と考えられ、誰に何を頼みますか。- 「取引先に送ったメールが届いていないと言われた」と利用者から連絡がありました。分かっているのは送信日時と宛先だけです。自組織のログと相手への依頼で、何を手がかりに追いますか。
ヒント:この記事の「下の層から順に確かめる」図とTcpClientの方法、Certificate chainの図と連載「証明書入門」第5回、Message-IDとキューIDの図が答えにつながります。
まとめ
- 名前解決 → TCP → SMTP → TLS → 認証の順に、下の層から確かめる。最初に失敗した段に原因がある
- 疎通は送信元の機器から試す。timed outは遮断、Connection refusedは待ち受けなし
- 手でSMTPを話すなら、Linuxはnc -C、WindowsはPowerShellのTcpClient。RCPT TOまでで止めれば送られない
- TLSはopenssl s_client -starttls smtpかSslStream。Certificate chainはi:が次のs:につながるか
- AUTHのBase64は暗号ではない。履歴にパスワードを残さない
- Send-MailMessageは非推奨。試験送信はswaks
- 1通を追うのはMessage-ID、サーバーの中を追うのはキューID。またぐときはqueued as
次回は、Microsoft 365・Google Workspace・Amazon SESといったクラウドのメールと、機器からの通知メールの送り方を扱います。
連載「メール入門」全12回
- メールが届くまで
- SMTPのやり取り
- メッセージの構造
- ポートと暗号化・認証
- 送信ドメイン認証 前編
- 送信ドメイン認証 後編
- 迷惑メール対策と配信
- MTAの運用
- コマンドで調べる(この記事)
- クラウドと現代のメール
- メールのトラブルシュート
- メールの設計演習


コメント