====== 【PHP】imap_open で「Couldn't open stream」エラーが出る ====== メールサーバを自作し、imap_open でメールサーバにある受信メールを取得するプログラムを作成していた際に遭遇したエラーとその対処法について。\\ ==== 遭遇したエラー ==== SSL / TLS を使用して POP3 / IMAP でメールを取得しようとしたところエラーが発生。 === Laravel でのエラー表示 === > ErrorException > imap_open(): Couldn't open stream {localhost:993/imap/ssl}INBOX === PHP エラーログ上の表示 === > PHP Fatal error: Uncaught ErrorException: Unknown: Certificate failure for localhost: Server name does not match certificate: /CN=example.com (errflg=2) in Unknown:0 > Stack trace: > #0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError() > #1 {main} > thrown in Unknown on line 0 === /var/log/maillog の内容 === > dovecot: imap-login: Disconnected (no auth attempts in 0 secs): user=<>, rip=127.0.0.1, lip=127.0.0.1, TLS, session= ==== 現象 ==== Postfix と Dovecot に SSL/TLS を導入する前は imap_open が成功していました。 (POP3:110番ポート、IMAP:143番ポート) $account = 'mail@example.com'; $password = 'PASSWORD'; # POP3 で接続(成功) $mailbox = '{localhost:110/pop3/notls}INBOX'; $mbox = imap_open($mailbox, $account, $password) or die('接続エラー: ' . imap_last_error()); imap_close($mbox); # IMAP で接続(成功) $mailbox = '{localhost:143/imap/notls}INBOX'; $mbox = imap_open($mailbox, $account, $password) or die('接続エラー: ' . imap_last_error()); imap_close($mbox); ところが、SSL/TLS を導入後 imap_open でエラーが出るようになりました。 (POP3S:995番ポート、IMAP4S:993番ポート) # POP3S で接続(失敗) $mailbox = '{localhost:995/pop3/ssl}INBOX'; $mbox = imap_open($mailbox, $account, $password) or die('接続エラー: ' . imap_last_error()); imap_close($mbox); # IMAP4S で接続(失敗) $mailbox = '{localhost:993/imap/ssl}INBOX'; $mbox = imap_open($mailbox, $account, $password) or die('接続エラー: ' . imap_last_error()); imap_close($mbox); ==== 解決方法 ==== 「/novalidate-cert」を付けるだけ。。。 # POP3S で接続(成功) $mailbox = '{localhost:995/pop3/ssl/novalidate-cert}INBOX'; $mbox = imap_open($mailbox, $account, $password) or die('接続エラー: ' . imap_last_error()); imap_close($mbox); # IMAP4S で接続(成功) $mailbox = '{localhost:993/imap/ssl/novalidate-cert}INBOX'; $mbox = imap_open($mailbox, $account, $password) or die('接続エラー: ' . imap_last_error()); imap_close($mbox); デバッグ情報を表示するようにしたり、色々試した結果、最終的には [[https://www.php.net/manual/ja/function.imap-open.php#95959|PHPの公式ドキュメントにあるコメント]] の記述に助けられ、無事動くようになりました。 公式ドキュメントには「/novalidate-cert」オプションは、自己証明書を使っている際に必要、とあったので、Let's Encrypt を使用していた今回は関係ないと思っていたのですが、原理は分からないままなものの、このオプションを付けることで成功するようになりました。 ちなみに、Thunderbird などのメールソフトでは正常に送受信に成功しているので、証明書が間違っているということはありません。\\ なぜだ。。。