昨天分享了Javamail如何配置icloud邮箱拉取邮件,目前线上job运行良好。传送门 Javamail接收icloud邮件
在昨天的代码里我们的工具类使用了全局代理:
//设置代理(全局代理,system级别)
props.setProperty("proxySet", "true");
props.setProperty("socksProxyHost", socksProxyHost);
props.setProperty("socksProxyPort", socksProxyPort);
设置此代理,将影响Java程序整个进程,使得其他网络请求也会强制走此代理。在我的应用程序中,还调用了公司内部其他服务比如发送邮件,这些本可以走内网的请求也会使用代理通道无端饶了一大圈,既影响了性能也对代理产生一定负担。为此我开始研究如何使用局部代理。
在Javamail的api描述中,我看到了有关代理的一些介绍:如何配置JavaMail以通过我的代理服务器工作?
如果你的代理服务器支持SOCKS V4或V5协议,并允许匿名连接,而你正在使用JDK 1.5或更高版本,JavaMail 1.4 .5或更新的版本,您可以通过设置 javadoc中所述的 “mail.smtp.socks.host” 属性,以每个会话,每个协议为基础配置SOCKS代理 。“imap”和“pop3”协议存在类似的特性。
如果您使用的是较旧版本的JDK或JavaMail,则可以通知Java运行时将所有TCP套接字连接指向SOCKS服务器。请参阅 网络属性指南 ,以获取有关 socksProxyHost 和 socksProxyPort 属性的最新文档。这些是系统级属性,而不是JavaMail会话属性。该工具可用于将SMTP,IMAP和POP3通信从JavaMail指向SOCKS代理服务器。请注意,设置这些属性会将 TCP套接字指向SOCKS代理,这可能会对应用程序的其他方面产生负面影响。
于是我将代码改造(先将 javamail 包升级至1.4.5或以上,我用的1.4.7):
//屏蔽全局代理
//props.setProperty("proxySet", "true");
//props.setProperty("socksProxyHost", socksProxyHost);
//props.setProperty("socksProxyPort", socksProxyPort);
//设置局部代理(imap同理)
props.setProperty("mail.pop3.socks.host", socksProxyHost);
props.setProperty("mail.pop3.socks.port", socksProxyPort);
为了验证代理是否有效,我故意将mail 方法中的port 端口改成一个错误的8888
public static void main(String[] args) {
String protocol = "pop3";
String host = "pop.163.com";
String username = "[email protected]";
String password = "xxxx";
String deleteFlag = "false";
String socksProxyHost = "xxxx";
String socksProxyPort = "8888";
List list = ReceiveEmailTool.getEmailList(protocol, username, password, host, deleteFlag, socksProxyHost, socksProxyPort);
for(EmailEntity en:list){
System.out.println("主题:" + en.getSubject());
}
}
运行程序,发现成功读取到邮件,这说明代理并未生效!!!
主题:回复:ergou
主题:测试mail
主题:Re: 测试mail
主题:Re: 测试mail
主题:Re: 测试mail
为什么呢?明明版本已经升级了,也按照官方的api配置的,但是却不生效。接着继续查找资料,大约花费了几个小时,直到晚饭回来,无意中想起还有几个重要的参数被我忽视了:
props.setProperty("mail.pop3.socketFactory.port", "995");
props.setProperty("mail.pop3.socketFactory.fallback", "false");
props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
文档中的介绍是:
mail.pop3.socketFactory.port:指定在使用指定的套接字工厂时要连接的端口。如果未设置,则将使用默认端口。
mail.pop3.socketFactory.fallback:如果设置为true,则无法使用指定的套接字工厂类创建套接字将导致使用java.net.Socket类创建套接字。默认为true。
mail.pop3.socketFactory.class:如果设置,则指定实现javax.net.SocketFactory接口的类的名称。这个类将被用来创建POP3套接字。
似懂非懂的试着将这三行代码屏蔽,果然控制台输出连接失败,于是将端口号改成正确的1080,成功拉取。这也意味着使用局部代理成功了。
按照我的猜测,虽然配置了局部代理,但是由于配置了上述三行代码,jvm默认将使用指定的套接字工厂类创建jvm级别的套接字,因此覆盖了局部代理的范围,导致局部代理虽然端口号改错,也不影响全局代理。