接收Email


发送Email的过程我们在上一节已经讲过了,客户端总是通过SMTP协议把邮件发送给MTA。

接收Email则相反,因为邮件最终到达收件人的MDA服务器,所以,接收邮件是收件人用自己的客户端把邮件从MDA服务器上抓取到本地的过程。

接收邮件使用最广泛的协议是POP3:Post Office Protocol version 3,它也是一个建立在TCP连接之上的协议。POP3服务器的标准端口是110,如果整个会话需要加密,那么使用加密端口995。

另一种接收邮件的协议是IMAP:Internet Mail Access Protocol,它使用标准端口143和加密端口993。IMAP和POP3的主要区别是,IMAP协议在本地的所有操作都会自动同步到服务器上,并且,IMAP可以允许用户在邮件服务器的收件箱中创建文件夹。

JavaMail也提供了IMAP协议的支持。因为POP3和IMAP的使用方式非常类似,因此我们只介绍POP3的用法。

使用POP3收取Email时,我们无需关心POP3协议底层,因为JavaMail提供了高层接口。首先需要连接到Store对象:

  1. // 准备登录信息:
  2. String host = "pop3.example.com";
  3. int port = 995;
  4. String username = "bob@example.com";
  5. String password = "password";
  6. Properties props = new Properties();
  7. props.setProperty("mail.store.protocol", "pop3"); // 协议名称
  8. props.setProperty("mail.pop3.host", host);// POP3主机名
  9. props.setProperty("mail.pop3.port", String.valueOf(port)); // 端口号
  10. // 启动SSL:
  11. props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
  12. props.put("mail.smtp.socketFactory.port", String.valueOf(port));
  13. // 连接到Store:
  14. URLName url = new URLName("pop3", host, post, "", username, password);
  15. Session session = Session.getInstance(props, null);
  16. session.setDebug(true); // 显示调试信息
  17. Store store = new POP3SSLStore(session, url);
  18. store.connect();

一个Store对象表示整个邮箱的存储,要收取邮件,我们需要通过Store访问指定的Folder(文件夹),通常是INBOX表示收件箱:

  1. // 获取收件箱:
  2. Folder folder = store.getFolder("INBOX");
  3. // 以读写方式打开:
  4. folder.open(Folder.READ_WRITE);
  5. // 打印邮件总数/新邮件数量/未读数量/已删除数量:
  6. System.out.println("Total messages: " + folder.getMessageCount());
  7. System.out.println("New messages: " + folder.getNewMessageCount());
  8. System.out.println("Unread messages: " + folder.getUnreadMessageCount());
  9. System.out.println("Deleted messages: " + folder.getDeletedMessageCount());
  10. // 获取每一封邮件:
  11. Message[] messages = folder.getMessages();
  12. for (Message message : messages) {
  13. // 打印每一封邮件:
  14. printMessage((MimeMessage) message);
  15. }

当我们获取到一个Message对象时,可以强制转型为MimeMessage,然后打印出邮件主题、发件人、收件人等信息:

  1. void printMessage(MimeMessage msg) throws IOException, MessagingException {
  2. // 邮件主题:
  3. System.out.println("Subject: " + MimeUtility.decodeText(msg.getSubject()));
  4. // 发件人:
  5. Address[] froms = msg.getFrom();
  6. InternetAddress address = (InternetAddress) froms[0];
  7. String personal = address.getPersonal();
  8. String from = personal == null ? address.getAddress() : (MimeUtility.decodeText(personal) + " <" + address.getAddress() + ">");
  9. System.out.println("From: " + from);
  10. // 继续打印收件人:
  11. ...
  12. }

比较麻烦的是获取邮件的正文。一个MimeMessage对象也是一个Part对象,它可能只包含一个文本,也可能是一个Multipart对象,即由几个Part构成,因此,需要递归地解析出完整的正文:

  1. String getBody(Part part) throws MessagingException, IOException {
  2. if (part.isMimeType("text/*")) {
  3. // Part是文本:
  4. return part.getContent().toString();
  5. }
  6. if (part.isMimeType("multipart/*")) {
  7. // Part是一个Multipart对象:
  8. Multipart multipart = (Multipart) part.getContent();
  9. // 循环解析每个子Part:
  10. for (int i = 0; i < multipart.getCount(); i++) {
  11. BodyPart bodyPart = multipart.getBodyPart(i);
  12. String body = getBody(bodyPart);
  13. if (!body.isEmpty()) {
  14. return body;
  15. }
  16. }
  17. }
  18. return "";
  19. }

最后记得关闭FolderStore

  1. folder.close(true); // 传入true表示删除操作会同步到服务器上(即删除服务器收件箱的邮件)
  2. store.close();

练习

接收Email - 图1下载练习:使用POP3接收邮件 (推荐使用IDE练习插件快速下载)

小结

使用Java接收Email时,可以用POP3协议或IMAP协议。

使用POP3协议时,需要用Maven引入JavaMail依赖,并确定POP3服务器的域名/端口/是否使用SSL等,然后,调用相关API接收Email。

设置debug模式可以查看通信详细内容,便于排查错误。

读后有收获可以支付宝请作者喝咖啡:

接收Email - 图2