501 Command "HELO" requires an argument問題的解決方法
場景描述:
保存郵箱配置時(shí)自動(dòng)探測郵箱配置參數(shù)是否正確,結(jié)果發(fā)現(xiàn)在探測SMTP時(shí),系統(tǒng)報(bào)出如下異常:
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)
但是換一個(gè)windows服務(wù)器,發(fā)現(xiàn)就沒這樣的問題,僅在一臺(tái)Linux服務(wù)器上可以重現(xiàn),直觀感覺就是這臺(tái)Linux服務(wù)器某些配置有問題。
排查步驟
1. 找一臺(tái)同樣操作系統(tǒng)的Linux服務(wù)器,驗(yàn)證郵箱配置,ok,排除Linux操作系統(tǒng)特殊性的問題
2. 直接在Linux服務(wù)器上使用telnet連接對(duì)端郵件服務(wù)器的SMTP端口,OK,排除該服務(wù)器的網(wǎng)絡(luò)問題
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.
發(fā)現(xiàn)HELO指令后面需要跟一個(gè)發(fā)起者的主機(jī)名,告訴SMTP服務(wù)器這個(gè)消息來源是哪里。
再看異常信息是"501 Command "HELO" requires an argument",很明顯,程序在跟SMTP SERVER交互過程中沒有傳遞源主機(jī)域名。
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方法在哪里被調(diào)用,看看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的獲取可以通過當(dāng)前連接的session屬性中獲取,也可以從當(dāng)前服務(wù)器的hosts配置中獲取,而我們程序是沒有在session中設(shè)置hostname的,因此原因肯定在于該臺(tái)Linux服務(wù)器的hosts文件被修改,造成JAVA程序無法自動(dòng)獲得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. 重新測試,問題解決了。
其實(shí),這種情況也可以通過程序避免,即在session連接中加入當(dāng)前服務(wù)器的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服務(wù)器連接失敗,請(qǐng)檢查輸入信息是否正確");
} catch (NoSuchProviderException e) {
e.printStackTrace();
System.out.println("smtp服務(wù)器連接失敗,請(qǐng)檢查輸入信息是否正確");
} catch (MessagingException e) {
e.printStackTrace();
System.out.println("smtp服務(wù)器連接失敗,請(qǐng)檢查輸入信息是否正確");
}
}
相關(guān)文章
Java實(shí)現(xiàn)的時(shí)間戳與date對(duì)象相互轉(zhuǎn)換功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的時(shí)間戳與date對(duì)象相互轉(zhuǎn)換功能,結(jié)合具體實(shí)例形式分析了java日期與時(shí)間戳類型的表示與轉(zhuǎn)換相關(guān)操作技巧,需要的朋友可以參考下2017-06-06java selenium教程之selenium詳細(xì)介紹
本文主要介紹Java selenium,這里整理了selenium的一些基本資料,此軟件主要用于Web UI自動(dòng)測試框架,有興趣的同學(xué)可以看一下2016-08-08mybatis/mybatis-plus模糊查詢語句特殊字符轉(zhuǎn)義攔截器的實(shí)現(xiàn)
在開發(fā)中,我們通常會(huì)遇到這樣的情況。用戶在錄入信息是錄入了‘%’,而在查詢時(shí)無法精確匹配‘%’。究其原因,‘%’是MySQL的關(guān)鍵字,如果我們想要精確匹配‘%’,那么需要對(duì)其進(jìn)行轉(zhuǎn)義,本文就詳細(xì)的介紹一下2021-11-11Spring Boot中使用Spring-Retry重試框架的實(shí)現(xiàn)
本文主要介紹了Spring Boot中使用Spring-Retry重試框架的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04SpringBoot?項(xiàng)目的創(chuàng)建與啟動(dòng)步驟詳解
這篇文章主要介紹了SpringBoot?項(xiàng)目的創(chuàng)建與啟動(dòng),本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03使用Java第三方實(shí)現(xiàn)發(fā)送短信功能
這篇文章主要介紹了使用Java第三方實(shí)現(xiàn)發(fā)送短信功能,在一些開發(fā)中,經(jīng)常需要有給用戶發(fā)送短信接收驗(yàn)證碼的功能,那么在Java中該如何實(shí)現(xiàn)呢,今天我們就一起來看一看2023-03-03java基于servlet實(shí)現(xiàn)文件上傳功能解析
這篇文章主要為大家詳細(xì)介紹了java基于servlet實(shí)現(xiàn)上傳功能,后臺(tái)使用java實(shí)現(xiàn),前端主要是js的ajax實(shí)現(xiàn),感興趣的小伙伴們可以參考一下2016-05-05