最近在做一个邮件拨测项目,服务端运行一个job,每隔一段时间向程序设定的目标邮箱发送批量测试邮件,使用 javamail sdk 拉取邮件,统计到达率,一旦出现到达率低的情况立即报警。
由于目标邮箱供应商众多,且用户多来自海外,在测试连接邮箱的时候遇到诸多问题。这里主要分享一下配合读取icloud邮箱是遇到的问题。
先上代码
//读取邮件,新建ReceiveEmailTool类
public static List getEmailList(String protocol, String username, String password, String host,
String deleteFlag, String socksProxyHost, String socksProxyPort) {
//要读取的邮件都在此文件夹下,不管已读未读
String foldName = "INBOX";
//SSL_FACTORY
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
List list = new ArrayList<>();
try {
Properties props = System.getProperties();
//设置代理
props.setProperty("proxySet", "true");
props.setProperty("socksProxyHost", socksProxyHost);
props.setProperty("socksProxyPort", socksProxyPort);
//协议,pop3或imap
props.setProperty("mail.store.protocol", protocol);
if (protocol.equals("pop3")) {
props.setProperty("mail.pop3.host", host);
props.setProperty("mail.pop3.port", "995");
props.setProperty("mail.pop3.auth", "true");
props.setProperty("mail.pop3.ssl.enable", "true");
props.setProperty("mail.pop3.socketFactory.port", "995");
props.setProperty("mail.pop3.socketFactory.fallback", "false");
props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
} else {
props.setProperty("mail.imap.host", host);
props.setProperty("mail.imap.port", "993");
props.setProperty("mail.imap.auth", "true");
props.setProperty("mail.imap.ssl.enable", "true");
props.setProperty("mail.imap.socketFactory.port", "993");
props.setProperty("mail.imap.socketFactory.fallback", "false");
props.setProperty("mail.imap.socketFactory.class", SSL_FACTORY);
}
// 获取连接
Session session = Session.getDefaultInstance(props);
session.setDebug(false);
// 获取Store对象
Store store = session.getStore(protocol);
store.connect(username, password);
Folder folder = store.getFolder(foldName);
folder.open(Folder.READ_WRITE); // 设置对邮件帐户的访问权限
Message[] messages = folder.getMessages();// 得到邮箱帐户中的所有邮件
for (Message message : messages) {
EmailEntity en = new EmailEntity();
en.setSubject(message.getSubject());// 获得主题
if (deleteFlag.equals("true")) {
message.setFlag(Flags.Flag.DELETED, true);//标记删除
}
list.add(en);
}
folder.close(true);// 关闭邮件夹对象,删除已标记的邮件,注意是彻底删除
store.close(); // 关闭连接对象
} catch (Throwable e) {
System.out.println(e.getMessage());
}
return list;
}
测试
public static void main(String[] args) {
String protocol = "imap";//icloud 邮箱只支持imap协议
String host = "imap.mail.me.com";//icloud 邮件服务器
String username = "youricloud";//填写@icloud.com前面的部分即可
String password = "xxxx-xxxx-xxxx-xxxx";//设置的第三方专用密码,参见:https://support.apple.com/zh-cn/HT202304
String deleteFlag = "false";// 是否标记删除
//公司环境必须走代理才能访问邮箱服务器
String socksProxyHost = "代理host";
String socksProxyPort = "代理端口";
List list = ReceiveEmailTool.getEmailList(protocol, username, password, host, deleteFlag, socksProxyHost, socksProxyPort);
for(EmailEntity en:list){
System.out.println("主题:" + en.getSubject());
}
}
以上代码分别验证通过了hotmail、naver、qq、outlook、163 等邮箱,使用的是pop3协议。但是因为icloud不支持pop3,所以走imap协议。运行上述代码,控制台报错输出:Authentication failed for ORACLE User。
解决方案:
最终在谷歌上搜到了一个类似的案例:How to use Javamail for accessing additional mailboxes (IMAP, Exchange 2010)
properties = System.getProperties();
properties.setProperty("mail.imaps.auth.plain.disable", "true");
properties.setProperty("mail.imaps.auth.ntlm.disable", "true");
Session session = Session.getInstance(properties, null);
store = session.getStore("imaps");
store.connect("HOST", PORT, "DOMAIN\\USER\\SHAREDACCOUNT","pwd");
于是我尝试着在代码里加上这两行,果然有效
props.setProperty("mail.imap.auth.plain.disable", "true");
props.setProperty("mail.imap.auth.ntlm.disable", "true");
查看一下这两个属性的意思,如果设置为true,则阻止AUTHENTICATE PLAIN 和 AUTHENTICATE NTLM 命令。默认为false。