利用javamail和POP3、SMTP协议实现邮件收发(转)

时间:2021-09-27 19:04:17

原文出处(http://java.chinaitlab.com/net/919396.html)

一、简介
  SMTP 的全称是"Simple Mail Transfer Protocol",即简单邮件传输协议,用于邮件发送。SMTP 认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器
  POP3(Post Office Protocol 3)协议允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等),不会反馈到服务器上,比如通过客户端收取了邮箱中的3封邮件并移动到其他文件夹,邮箱服务器上的这些邮件是没有同时被移动的 .
  而IMAP(Internet Mail Access Protocol)提供webmail 与电子邮件客户端之间的双向通信,客户端的操作都会反馈到服务器上,对邮件进行的操作,服务器上的邮件也会做相应的动作。
  同时,IMAP像POP3那样提供了方便的邮件下载服务,让用户能进行离线阅读。IMAP提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才作出是否下载的决定。此外,IMAP 更好地支持了从多个不同设备中随时访问新邮件。
  总之,IMAP 整体上为用户带来更为便捷和可靠的体验。POP3 更易丢失邮件或多次下载相同的邮件,但 IMAP 通过邮件客户端与webmail 之间的双向同步功能很好地避免了这些问题。
  注:若在web邮箱中设置了"保存到已发送",使用客户端POP服务发信时,已发邮件也会自动同步到网页端"已发送"文件夹内
  二、利用SMTP协议发送邮件
  package com.like.email;
  import java.io.File;
  import java.io.UnsupportedEncodingException;
  import java.util.ArrayList;
  import java.util.Properties;
  import javax.activation.DataHandler;
  import javax.activation.DataSource;
  import javax.activation.FileDataSource;
  import javax.mail.Authenticator;
  import javax.mail.BodyPart;
  import javax.mail.Message;
  import javax.mail.MessagingException;
  import javax.mail.Multipart;
  import javax.mail.Session;
  import javax.mail.Transport;
  import javax.mail.internet.AddressException;
  import javax.mail.internet.InternetAddress;
  import javax.mail.internet.MimeBodyPart;
  import javax.mail.internet.MimeMessage;
  import javax.mail.internet.MimeMultipart;
  /**
  * @author like
  * @E-mail kelee1987@hotmail.com
  * @CreateTime 2012-10-26 下午2:19:11
  */
  public class SMTPSendTest {
  private static final int RECEIPT = 1;
  private static final String attachmentDir = "";
  public static void sendEmail(Email emailInfo) throws UnsupportedEncodingException, MessagingException {
  Properties props = new Properties();
  props.put("mail.smtp.host", emailInfo.getSmtpServer());
  props.put("mail.smtp.port", emailInfo.getSmtpPort());
  props.put("mail.smtp.auth", "true");
  Authenticator auth = new SMTPAuthenticator(emailInfo.getUsername(), emailInfo.getPassword());
  Session session = Session.getInstance(props, auth);
  session.setDebug(false);
  Message msg = new MimeMessage(session);
  msg.setFrom(new InternetAddress(emailInfo.getFrom(), emailInfo.getFromName()));
  msg.setRecipients(Message.RecipientType.TO, getEmailRecipient(emailInfo.getTO()));
  msg.setRecipients(Message.RecipientType.CC, getEmailRecipient(emailInfo.getCC()));
  msg.setRecipients(Message.RecipientType.BCC, getEmailRecipient(emailInfo.getBCC()));
  if (emailInfo.getReceipt() == RECEIPT) {
  msg.setHeader("Disposition-Notification-To", emailInfo.getFrom());
  }
  msg.setSubject(emailInfo.getSubject());
  // 设置邮件内容(包括附件的HTML格式内容)
  msg.setContent(getMultipart(emailInfo.getContent(), attachmentDir, emailInfo.getAttachment()));
  msg.saveChanges();
  Transport.send(msg);
  }
  /**
  * 封装邮件地址
  *
  * @param address
  * @return
  * @throws AddressException
  */
  private static InternetAddress[] getEmailRecipient(ArrayList<String> address) throws AddressException {
  int toLen = 0;
  if (address != null) {
  toLen = address.size();
  }
  InternetAddress[] addressTo = new InternetAddress[toLen];
  if (toLen != 0) {
  String m_st_email = "";
  for (int i = 0; i < toLen; i++) {
  m_st_email = (String) address.get(i);
  if (m_st_email != null)
  addressTo[i] = new InternetAddress(m_st_email.trim());
  }
  }
  return addressTo;
  }
   private static Multipart getMultipart(String text, String attachParentDir, ArrayList<String> attachment) throws MessagingException {

// 混合型邮件内容
  Multipart multi = new MimeMultipart("mixed");// 混合MIME消息
  // 加入文本内容
  multi.addBodyPart(createContent(text));
  // 加入附件内容
  for (int i = 0; i < attachment.size(); i++) {
  String attachmentI = (String) attachment.get(i);
  // 附件的真是存储名称
  String fileRealName = attachmentI.substring(attachmentI.indexOf("<") + 1)。trim();
  // 附件在邮件中的显示名称
  String fileShowName = attachmentI.substring(0, attachmentI.indexOf(">"));
  multi.addBodyPart(createAttachment(fileShowName, new File(attachParentDir + fileRealName)));// 嵌入附件
  }
  return multi;
  }
  /**
  * 邮件附件的处理
  *
  * @param fileName
  *            附件显示名称
  * @param file
  *            文件
  * @return javax.mail.BodyPart(javaMail的邮件内容)
  * @throws MessagingException
  */
  private static BodyPart createAttachment(String fileName, File file) throws MessagingException {
  BodyPart attach = new MimeBodyPart();
  DataSource ds = new FileDataSource(file);
  attach.setDataHandler(new DataHandler(ds));
  try {
  // 文件名重新编码,解决乱码问题
  attach.setFileName(new String(fileName.getBytes(), "ISO8859-1"));
  } catch (UnsupportedEncodingException e) {
  e.printStackTrace();
  }
  return attach;
  }
  /**
  * 邮件文本内容的处理
  *
  * @param text
  *            文本内容
  * @return javax.mail.BodyPart(javaMail的邮件内容)
  * @throws MessagingException
  */
  private static BodyPart createContent(String text) throws MessagingException {
  BodyPart content = new MimeBodyPart();
  // 邮件正文也是一种组合消息,可以包含多个MimeBodyPart
  Multipart relate = new MimeMultipart("related");
  BodyPart html = new MimeBodyPart();
  html.setContent(text, "text/html;charset=gbk");
  relate.addBodyPart(html);
  content.setContent(relate);
  return content;
  }
  }
  邮件内容结构图:
  三、POP3协议接受邮件
  package com.like.email;
  import java.util.Properties;
  import javax.mail.Authenticator;
  import javax.mail.Flags;
  import javax.mail.Folder;
  import javax.mail.Message;
  import javax.mail.MessagingException;
  import javax.mail.Session;
  import javax.mail.Store;
  import com.sun.mail.pop3.POP3Folder;
  /**
  * POP3协议虽然相较IMAP协议有明显劣势,但仍然使用广泛,而且并不是所有的邮件服务器都支持IMAP协议。
  * @author like
  * @E-mail  kelee1987@hotmail.com
  * @CreateTime 2012-10-26 下午4:25:23
  */
  public class OP3Test {
   public static void receive(String server, int port, String username, String password, boolean isDelete) throws MessagingException {
  Properties props = System.getProperties();
  Authenticator auth = new POPAuthenticator(username, password);
  Session session = Session.getInstance(props, auth);
  session.setDebug(false);
  Store store = session.getStore("POP3");
  store.connect(server, port, username, password);
  //获得收件箱
  POP3Folder folder = (POP3Folder) store.getFolder("INBOX");
  try {
  //读写方式打开
  folder.open(Folder.READ_WRITE);
  } catch (MessagingException ex) {
  //制度方式打开
  folder.open(Folder.READ_ONLY);
  }
  // int totalMessages = folder.getMessageCount();
  Message m_message = null;
  Message[] msgs = folder.getMessages();
  for (int i = 0; i < msgs.length; i++) {
  m_message = msgs[i];
  String UID = folder.getUID(m_message);
  if (haveReceived(UID)) {
  // 插入数据库
  // mailList.add(new RecvMailTask(m_message,
  // p_st_attachmentParentDir, UID));
  // 设置为已读,IMAP协议支持,POP3协议不支持该功能
  m_message.setFlag(Flags.Flag.SEEN, true);
  // POP3协议可以删除
  m_message.setFlag(Flags.Flag.DELETED, isDelete);
  }
  }
  }
  /**
  * POP3协议的对邮件的操作和服务器不同步,不能区分是否为已读邮件。 如果接收后不删除服务器上的邮件,下次仍然会接收该邮件。
  * 服务器会给每一封邮件一个独一无二的UID,接收邮件时保存该UID到数据库,作为下次接收时是否已经接收过该邮件的依据。
  * 有两种方式:(1)每次接收先从数据库中读取所有的UID,接收时判断是否包含当次接收邮件的UID.
  * 优点是只读一次数据库,缺点是读出的UID数量可能会很多。
  *  (2)接收每一封邮件时,把其UID作为参数查询数据库,是否返回数据作为判断依据。
  *
  * @param UID
  * @return
  */
  private static boolean haveReceived(String UID) {
  //个人觉得第一种较好,如果邮箱中邮件较多,接收又较为频繁,那么每次接收都会产生大量数据库连接次数。
  //第一种注意把取得的UID集放入到Set集合中,用contains()方法直接判断
  return true;
  }