501 Command "HELO" requires an argument問題的解決方案_java

來源:互聯網
上載者:User

情境描述:
儲存郵箱配置時自動探測郵箱配置參數是否正確,結果發現在探測SMTP時,系統報出如下異常:

複製代碼 代碼如下:

javax.mail.MessagingException: 501 Command "HELO" requires an argument
        at com.sun.mail.smtp.SMTPTransport.issueCommand(SMTPTransport.java:1363)
        at com.sun.mail.smtp.SMTPTransport.helo(SMTPTransport.java:838)
        at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:375)
        at javax.mail.Service.connect(Service.java:275)

但是換一個windows伺服器,發現就沒這樣的問題,僅在一台Linux伺服器上可以重現,直觀感覺就是這台Linux伺服器某些配置有問題。

排查步驟
1. 找一台同樣作業系統的Linux伺服器,驗證郵箱配置,ok,排除Linux作業系統特殊性的問題
2. 直接在Linux伺服器上使用telnet串連對端郵件伺服器的SMTP連接埠,OK,排除該伺服器的網路問題
3. 尋找HELO指令解釋
複製代碼 代碼如下:

HELO
-- Initiates a conversation with the mail server. When using this command you can specify your domain name so that the mail server knows who you are. For example, HELO mailhost2. cf.ac.uk.

發現HELO指令後面需要跟一個發起者的主機名稱,告訴SMTP伺服器這個訊息來源是哪裡。
再看異常資訊是"501 Command "HELO" requires an argument",很明顯,程式在跟SMTP SERVER互動過程中沒有傳遞源主機網域名稱。

4. 查看JAVA MAIL源碼
尋找HELO指令,如下:

複製代碼 代碼如下:

        /**
         * Issue the <code>HELO</code> command.
         *
         * @param domain
         *            our domain
         *
         * @since JavaMail 1.4.1
         */
        protected void helo(String domain) throws MessagingException {
                if (domain != null)
                        issueCommand("HELO " + domain, 250);
                else
                        issueCommand("HELO", 250);
        }

尋找helo方法在哪裡被調用,看看domain如何被傳遞過來的
複製代碼 代碼如下:

                if (useEhlo)
                        succeed = ehlo(getLocalHost());
                if (!succeed)
                        helo(getLocalHost());

順理成章,接著找getLocalHost()方法,定義如下:
複製代碼 代碼如下:

        /**
         * Get the name of the local host, for use in the EHLO and HELO commands.
         * The property mail.smtp.localhost overrides mail.smtp.localaddress, which
         * overrides what InetAddress would tell us.
         */
        public synchronized String getLocalHost() {
                try {
                        // get our hostname and cache it for future use
                        if (localHostName == null || localHostName.length() <= 0)
                                localHostName = session.getProperty("mail." + name + ".localhost");
                        if (localHostName == null || localHostName.length() <= 0)
                                localHostName = session.getProperty("mail." + name+ ".localaddress");
                        if (localHostName == null || localHostName.length() <= 0) {
                                InetAddress localHost = InetAddress.getLocalHost();
                                localHostName = localHost.getHostName();
                                // if we can't get our name, use local address literal
                                if (localHostName == null)
                                        // XXX - not correct for IPv6
                                        localHostName = "[" + localHost.getHostAddress() + "]";
                        }
                } catch (UnknownHostException uhex) {
                }
                return localHostName;
        }

可以看到hostname的擷取可以通過當前串連的session屬性中擷取,也可以從當前伺服器的hosts配置中擷取,而我們程式是沒有在session中設定hostname的,因此原因肯定在於該台Linux伺服器的hosts檔案被修改,造成JAVA程式無法自動獲得localhostName。

5. 查看/etc/hosts檔案,情況如下:

複製代碼 代碼如下:

127.0.0.1              localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6

簡單的將hosts檔案修改如下:
複製代碼 代碼如下:

127.0.0.1       localhost
::1             localhost6.localdomain6 localhost6

6. 重新測試,問題解決了。
其實,這種情況也可以通過程式避免,即在session串連中加入當前伺服器的hostname屬性,程式樣本:
複製代碼 代碼如下:

        public static void main(String[] args) {
                try {
                        int smtpport = 25;
                        String smtpserver = "219.147.xxx.xxx";
                        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");
                        System.out.println("connect ok");
                        transport.close();
                } catch (AuthenticationFailedException en) {
                        en.printStackTrace();
                        System.out.println("smtp伺服器串連失敗,請檢查輸入資訊是否正確");
                } catch (NoSuchProviderException e) {
                        e.printStackTrace();
                        System.out.println("smtp伺服器串連失敗,請檢查輸入資訊是否正確");
                } catch (MessagingException e) {
                        e.printStackTrace();
                        System.out.println("smtp伺服器串連失敗,請檢查輸入資訊是否正確");
                }
        }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.