Javamail 使用局部代理

昨天分享了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服务器。请参阅 网络属性指南 ,以获取有关 socksProxyHostsocksProxyPort 属性的最新文档。这些是系统级属性,而不是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 = "zhaoyuan7845@163.com";
        String password = "xxxx";
        String deleteFlag = "false";
        String socksProxyHost = "xxxx";
        String socksProxyPort = "8888";
        List<EmailEntity> 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。