在使用 JavaMail 進行 SMTP 郵件發送測試時,偶爾會遇到 javax.mail.MessagingException: 501 Command "HELO" requires an argument 這類錯誤。錯誤堆疊通常指向 SMTPTransport.helo() 方法,提示 HELO 指令缺少必要的參數——發送端的主機名或域名。這篇文章記錄一次在 Linux 伺服器上排查並解決此問題的完整過程,供開發者參考。
專案在保存郵箱配置時,會主動探測 SMTP 連線是否正常。在大多數 Windows 伺服器上測試通過,但某台 Linux 伺服器卻持續拋出上述異常。直覺判斷是該 Linux 環境的特定配置導致 Java 程式無法正確獲取本機主機名。
telnet 目標郵件伺服器的 SMTP 埠(25),連線成功,網路無阻礙。HELO <domain> 必須攜帶發送方的主機名/域名,以便接收方識別來源。錯誤訊息明確指出「requires an argument」,即程式在交互時未傳遞此參數。SMTPTransport.helo(String domain) 方法,發現當 domain 為 null 時,會發送不帶參數的 HELO 指令,直接觸發 501 錯誤。進一步查看 getLocalHost() 方法,其獲取主機名的邏輯依賴:
mail.smtp.localhostmail.smtp.localaddressInetAddress.getLocalHost().getHostName()/etc/hosts,發現配置如下:
127.0.0.1 localhost.localdomain localhost ::1 localhost6.localdomain6 localhost6這導致
InetAddress.getLocalHost() 解析到的主機名可能為 localhost.localdomain 或解析失敗,進而導致 JavaMail 獲取不到有效的主機名參數。
將 /etc/hosts 中的回環地址對應簡化,確保主機名解析正確:
127.0.0.1 localhost ::1 localhost6.localdomain6 localhost6
修改後重新測試,問題即刻解決。
在建立 Session 時,透過 mail.smtp.localhost 屬性強制指定主機名:
Properties prop = System.getProperties();
prop.put("mail.smtp.auth", "true");
prop.put("mail.smtp.localhost", "myMailServer"); // 自定義一個合法的主機名
Session mailSession = Session.getInstance(prop, null);
Transport transport = mailSession.getTransport("smtp");
transport.connect(smtpServer, smtpPort, "username", "password");
此法繞過系統解析,直接提供 HELO 所需參數,同樣能解決問題。
此錯誤的核心在於 JavaMail 在發送 HELO 指令前,無法從運行環境獲取有效的本機主機名。Linux 下 /etc/hosts 配置不當是常見誘因。最佳實踐是確保作業系統層面的主機名解析正確;若環境受限,在 JavaMail 連線屬性中顯式設定 mail.smtp.localhost 即可繞過此限制。