Java使用JavaMail收发Email电子邮件

女爷i 2023-01-03 15:29 990阅读 0赞

使用JavaMail收发送电子邮件,包括带有附件和内嵌图片的邮件!

Email就是电子邮件。发邮件是从客户端把邮件发送到邮件服务器,收邮件是把邮件服务器的邮件下载到客户端,Java同样提供了收发邮件的API。

在这里插入图片描述

163、126、QQ、sohu、sina等网站都提供了邮件服务,这些网站都有自己的邮件服务器,我们自己的Email用户页面实际上就相当于客户端。

文章目录

  • 1 邮件协议
    • 1.1 邮件协议
    • 1.2 理解电子邮件收发过程
    • 1.3 邮件服务器名称
  • 2 JavaMail
    • 2.1 JavaMail概述
    • 2.2 maven依赖
    • 2.3 JavaMail发送邮件
      • 2.3.1 简单邮件
      • 2.3.2 发送HTML文本
      • 2.3.3 发送附件
      • 2.3.4 发送内嵌图片HTML
    • 2.4 JavaMail收取邮件
    • 2.5 相关异常
  • 3 总结

1 邮件协议

1.1 邮件协议

与HTTP协议相同,收发邮件也是需要有传输协议的:

  1. SMTP:(Simple Mail Transfer Protocol,简单邮件传输协议)发邮件协议;
  2. POP3:(Post Office Protocol Version 3,邮局协议第3版)收邮件协议;
  3. IMAP:(Internet Message Access Protocol,因特网消息访问协议)收发邮件协议。

这些协议都属于应用层协议。

1.2 理解电子邮件收发过程

其实你可以把邮件服务器理解为邮局!如果你需要给朋友寄一封信,那么你需要把信放到邮筒中,这样你的信会“自动”到达邮局,邮局会把信邮到另一个省市的邮局中。然后这封信会被送到收信人的邮箱中。最终收信人需要自己经常查看邮箱是否有新的信件。

其实每个邮件服务器都由SMTP服务器和POP3服务器构成,其中SMTP服务器负责发邮件的请求,而POP3负责收邮件的请求。

在这里插入图片描述

当然,有时我们也会使用163的账号,向126的账号发送邮件。这时邮件是发送到126的邮件服务器,而对于163的邮件服务器是不会存储这封邮件的。

在这里插入图片描述

1.3 邮件服务器名称

smtp服务器的端口号为25,服务器名称为smtp.xxx.xxx。

pop3服务器的端口号为110,服务器名称为pop3.xxx.xxx。

例如:

  1. 163: smtp.163.com和pop3.163.com;
  2. 126: smtp.126.com和pop3.126.com;
  3. qq: smtp.qq.com和pop3.qq.com;
  4. sohu: smtp.sohu.com和pop3.sohu.com;
  5. sina: smtp.sina.com和pop3.sina.com。

2 JavaMail

2.1 JavaMail概述

JavaMail是由SUN公司提供的专门用于Java收发邮件的API,使用Java程序发送邮件时,我们无需关心SMTP协议的底层原理,只需要使用JavaMail这个标准API就可以直接发送邮件。

JavaMail中主要类有javax.mail.Session、javax.mail.internet.MimeMessage、javax.mail.Transport

  1. Session: 表示会话,即客户端与邮件服务器之间的会话!想获得会话需要给出账户和密码,当然还要给出服务器名称。在邮件服务中的Session对象,就相当于连接数据库时的Connection对象。
  2. MimeMessage: 表示邮件类,它是Message的子类。它包含邮件的主题(标题)、内容,收件人地址、发件人地址,还可以设置抄送和暗送,甚至还可以设置附件。
  3. Transport: 用来发送邮件。它是发送器!

2.2 maven依赖

使用JavaMail的API我们需要引入对应的jar包或者maven依赖:

  1. <!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
  2. <dependency>
  3. <groupId>com.sun.mail</groupId>
  4. <artifactId>javax.mail</artifactId>
  5. <version>1.6.2</version>
  6. </dependency>

jar包下载地址为:https://mvnrepository.com/artifact/com.sun.mail/javax.mail/1.6.2。

在这里插入图片描述

2.3 JavaMail发送邮件

我们使用smtp协议发送邮件!

2.3.1 简单邮件

发送一个简单的邮件需要三步:

  1. 根据服务器参数和认证器信息来获取Session实例;
  2. 根据Session创建MimeMessage对象,MimeMessage中包含了各种可以设置的邮件属性
  3. 通过Transport发送邮件

简单的案例如下:

  1. /**
  2. * @author lx
  3. */
  4. public class SimpleSendEmail {
  5. public static void main(String[] args) throws MessagingException {
  6. /*
  7. * 1 获取Session
  8. */
  9. /*设置服务器参数*/
  10. Properties props = new Properties();
  11. //设置服务器主机名
  12. props.put("mail.smtp.host", "smtp.163.com");
  13. //设置需要认证
  14. props.put("mail.smtp.auth", "true");
  15. // 启用TLS加密
  16. props.put("mail.smtp.starttls.enable", "true");
  17. /*
  18. * 根据服务器参数集合和认证器来获取Session实例
  19. *
  20. * Authenticator是一个接口表示认证器,即校验客户端的身份。
  21. * 我们需要自己来实现这个接口,实现这个接口需要使用账户和密码。
  22. */
  23. Session session = Session.getInstance(props, new Authenticator() {
  24. @Override
  25. protected PasswordAuthentication getPasswordAuthentication() {
  26. //使用自己的账户和密码,有些邮件服务器可能需要的是申请的授权码
  27. return new PasswordAuthentication("xxxx@163.com", "xxxx");
  28. }
  29. });
  30. // 设置debug模式,将会输出日志信息
  31. session.setDebug(true);
  32. /*
  33. * 2 根据Session创建MimeMessage对象
  34. *
  35. * MimeMessage中包含了各种可以设置的邮件属性
  36. */
  37. MimeMessage msg = new MimeMessage(session);
  38. //设置发信人
  39. msg.setFrom(new InternetAddress("xxx@163.com"));
  40. //设置收信人,可以设置多个,采用参数数组或者","分隔
  41. msg.addRecipients(TO, "xxx@qq.com");
  42. //设置抄送人,可以设置多个,采用参数数组或者","分隔
  43. msg.addRecipients(CC, "xxx@yeah.net");
  44. //设置暗送人,可以设置多个,采用参数数组或者","分隔
  45. msg.addRecipients(BCC, "xxx@xx.com");
  46. //设置邮件主题(标题)
  47. msg.setSubject("第一封邮件");
  48. //设置邮件内容(正文)和类型
  49. msg.setContent("说点啥呢?", "text/plain;charset=utf-8");
  50. /*
  51. * 3 发送邮件
  52. */
  53. Transport.send(msg);
  54. }
  55. }

2.3.2 发送HTML文本

有时候我们的邮件正文可能是一个HTML页面,发送方式和上面的案例完全一致,只需要注意编码格式为“text/html;charset=utf-8”,后面的字符集要与html文本的字符集一致。

当然,也可以发送图片资源等等。

  1. /**
  2. * @author lx
  3. */
  4. public class SendHtmlEmail {
  5. public static void main(String[] args) throws MessagingException {
  6. /*
  7. * 1 获取Session
  8. */
  9. /*设置服务器参数*/
  10. Properties props = new Properties();
  11. //设置服务器主机名
  12. props.put("mail.smtp.host", "smtp.163.com");
  13. //设置需要认证
  14. props.put("mail.smtp.auth", "true");
  15. // 启用TLS加密
  16. props.put("mail.smtp.starttls.enable", "true");
  17. /*
  18. * 根据服务器参数集合和认证器来获取Session实例
  19. *
  20. * Authenticator是一个接口表示认证器,即校验客户端的身份。
  21. * 我们需要自己来实现这个接口,实现这个接口需要使用账户和密码。
  22. */
  23. Session session = Session.getInstance(props, new Authenticator() {
  24. @Override
  25. protected PasswordAuthentication getPasswordAuthentication() {
  26. //使用自己的账户和密码,有些邮件服务器可能需要的是授权码
  27. return new PasswordAuthentication("xx@163.com", "xxx");
  28. }
  29. });
  30. // 设置debug模式,将会输出日志信息
  31. session.setDebug(true);
  32. /*
  33. * 2 根据Session创建MimeMessage对象
  34. *
  35. * MimeMessage中包含了各种可以设置的邮件属性
  36. */
  37. MimeMessage msg = new MimeMessage(session);
  38. //设置发信人
  39. msg.setFrom(new InternetAddress("x@163.com"));
  40. //设置收信人,可以设置多个,采用参数数组或者","分隔
  41. msg.addRecipients(TO, "xx@qq.com");
  42. //设置抄送人,可以设置多个,采用参数数组或者","分隔
  43. msg.addRecipients(CC, "xxx@yeah.net");
  44. //设置暗送人,可以设置多个,采用参数数组或者","分隔
  45. msg.addRecipients(BCC, "xxx@ikang.com");
  46. //设置邮件主题(标题)
  47. msg.setSubject("HTML邮件");
  48. //设置邮件内容(正文)和类型
  49. msg.setContent("<h2><font color=red>2021加油哦!</font></h2>", "text/html;charset =utf-8");
  50. /*
  51. * 3 发送邮件
  52. */
  53. Transport.send(msg);
  54. }
  55. }

结果:

在这里插入图片描述

2.3.3 发送附件

如果想发送带有附件邮件,那么需要设置邮件的内容为MimeMultiPart,而不仅仅是一段文本。

多部件对象MimeMultiPart,可以理解为是部件的集合。一个Multipart对象可以添加若干个BodyPart,其中第一个BodyPart是文本,即邮件正文,后面的BodyPart是附件,最后将MimeMultiPart设置到msg的content中。

在这里插入图片描述

案例如下:

  1. /**
  2. * @author lx
  3. */
  4. public class SendMultipartEmail {
  5. public static void main(String[] args) throws MessagingException, IOException {
  6. /*
  7. * 1 获取Session
  8. */
  9. /*设置服务器参数*/
  10. Properties props = new Properties();
  11. //设置服务器主机名
  12. props.put("mail.smtp.host", "smtp.163.com");
  13. //设置需要认证
  14. props.put("mail.smtp.auth", "true");
  15. // 启用TLS加密
  16. props.put("mail.smtp.starttls.enable", "true");
  17. /*
  18. * 根据服务器参数集合和认证器来获取Session实例
  19. *
  20. * Authenticator是一个接口表示认证器,即校验客户端的身份。
  21. * 我们需要自己来实现这个接口,实现这个接口需要使用账户和密码。
  22. */
  23. Session session = Session.getInstance(props, new Authenticator() {
  24. @Override
  25. protected PasswordAuthentication getPasswordAuthentication() {
  26. //使用自己的账户和密码,有些邮件服务器可能需要的是申请的授权码
  27. return new PasswordAuthentication("ccc@163.com", "ccc");
  28. }
  29. });
  30. // 设置debug模式,将会输出日志信息
  31. session.setDebug(true);
  32. /*
  33. * 2 根据Session创建MimeMessage对象
  34. *
  35. * MimeMessage中包含了各种可以设置的邮件属性
  36. */
  37. MimeMessage msg = new MimeMessage(session);
  38. //设置发信人
  39. msg.setFrom(new InternetAddress("ccc@163.com"));
  40. //设置收信人,可以设置多个,采用参数数组或者","分隔
  41. msg.addRecipients(TO, "ccc@qq.com");
  42. //设置抄送人,可以设置多个,采用参数数组或者","分隔
  43. msg.addRecipients(CC, "cc@yeah.net");
  44. //设置暗送人,可以设置多个,采用参数数组或者","分隔
  45. msg.addRecipients(BCC, "c@ikang.com");
  46. //设置邮件主题(标题)
  47. msg.setSubject("附件");
  48. //设置邮件内容(正文)和类型
  49. //msg.setContent("<h2><font color=red>2021加油哦!</font></h2>", "text/html;charset =utf-8");
  50. /*
  51. * 创建一个多部件对象Multipart,可以理解为是部件的集合。
  52. * 一个Multipart对象可以添加若干个BodyPart,其中第一个BodyPart是文本,即邮件正文,后面的BodyPart是附件
  53. */
  54. Multipart parts = new MimeMultipart();
  55. /*
  56. * 设置邮件的内容为多部件内容。
  57. */
  58. msg.setContent(parts);
  59. /*
  60. * 创建第一个部件,为邮件正文
  61. */
  62. BodyPart contentPart = new MimeBodyPart();
  63. //给部件设置正文内容
  64. contentPart.setContent("<h2><font color=red>附件来了!</font></h2>", "text/html;charset=utf-8");
  65. //把部件添加到部件集中
  66. parts.addBodyPart(contentPart);
  67. /*
  68. * 创建第二个附件部件,一张图片
  69. */
  70. MimeBodyPart imagepart = new MimeBodyPart();
  71. //设置附件名称
  72. imagepart.setFileName("people.jpg");
  73. //注意,如果在设置文件名称时,文件名称中包含了中文的话,那么需要使用MimeUitlity类来给中文编码:
  74. //imagepart.setFileName(MimeUtility.encodeText("中文.jpg"));
  75. //设置附件,二进制文件可以用application/octet-stream,Word文档则是application/msword。
  76. FileInputStream fileInputStream = new FileInputStream("email\\src\\main\\resources\\people.jpg");
  77. imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(fileInputStream, "application/octet-stream")));
  78. //把附件添加到部件集中
  79. parts.addBodyPart(imagepart);
  80. /*
  81. * 3 发送邮件
  82. */
  83. Transport.send(msg);
  84. }
  85. }

结果:

在这里插入图片描述

2.3.4 发送内嵌图片HTML

发送的HTML文本的内嵌图片可以采用网络链接,也可以使用本地图片。本地内嵌图片实际上也是一个附件,即邮件本身也是Multipart,但需要做一点额外的处理。

在HTML邮件中引用图片时,需要设定一个ID,用类似引用,然后,在添加图片作为BodyPart时,除了要正确设置MIME类型(根据图片类型使用image/jpeg或image/png),还需要设置ContentID为img1与HTML的中的img 标签的img1关联。

  1. /**
  2. * @author lx
  3. */
  4. public class SendPicEmail {
  5. public static void main(String[] args) throws MessagingException, IOException {
  6. /*
  7. * 1 获取Session
  8. */
  9. /*设置服务器参数*/
  10. Properties props = new Properties();
  11. //设置服务器主机名
  12. props.put("mail.smtp.host", "smtp.163.com");
  13. //设置需要认证
  14. props.put("mail.smtp.auth", "true");
  15. // 启用TLS加密
  16. props.put("mail.smtp.starttls.enable", "true");
  17. /*
  18. * 根据服务器参数集合和认证器来获取Session实例
  19. *
  20. * Authenticator是一个接口表示认证器,即校验客户端的身份。
  21. * 我们需要自己来实现这个接口,实现这个接口需要使用账户和密码。
  22. */
  23. Session session = Session.getInstance(props, new Authenticator() {
  24. @Override
  25. protected PasswordAuthentication getPasswordAuthentication() {
  26. //使用自己的账户和密码,有些邮件服务器可能需要的是申请的授权码
  27. return new PasswordAuthentication("xxx@163.com", "xx");
  28. }
  29. });
  30. // 设置debug模式,将会输出日志信息
  31. session.setDebug(true);
  32. /*
  33. * 2 根据Session创建MimeMessage对象
  34. *
  35. * MimeMessage中包含了各种可以设置的邮件属性
  36. */
  37. MimeMessage msg = new MimeMessage(session);
  38. //设置发信人
  39. msg.setFrom(new InternetAddress("cc@163.com"));
  40. //设置收信人,可以设置多个,采用参数数组或者","分隔
  41. msg.addRecipients(TO, "dd@ikang.com");
  42. //设置抄送人,可以设置多个,采用参数数组或者","分隔
  43. msg.addRecipients(CC, "cc@yeah.net");
  44. //设置暗送人,可以设置多个,采用参数数组或者","分隔
  45. msg.addRecipients(BCC, "xx@qq.com");
  46. //设置邮件主题(标题)
  47. msg.setSubject("这是一封图片HTML邮件");
  48. //设置邮件内容(正文)和类型
  49. //msg.setContent("<h2><font color=red>2021加油哦!</font></h2>", "text/html;charset =utf-8");
  50. /*
  51. * 创建一个多部件对象Multipart,可以理解为是部件的集合。
  52. * 一个Multipart对象可以添加若干个BodyPart,其中第一个BodyPart是文本,即邮件正文,后面的BodyPart是附件
  53. */
  54. Multipart parts = new MimeMultipart();
  55. /*
  56. * 设置邮件的内容为多部件内容。
  57. */
  58. msg.setContent(parts);
  59. /*
  60. * 创建第一个部件,为邮件正文
  61. */
  62. BodyPart contentPart = new MimeBodyPart();
  63. //给部件设置正文内容
  64. contentPart.setContent("<h1>Hello图片来了!</h1><p><img src='cid:img1'></p>", "text/html;charset=utf-8");
  65. //把部件添加到部件集中
  66. parts.addBodyPart(contentPart);
  67. /*
  68. * 创建第二个部件,一张图片,html中的图片也算作附件
  69. */
  70. MimeBodyPart imagepart = new MimeBodyPart();
  71. //设置附件名称
  72. imagepart.setFileName("people.jpg");
  73. //注意,如果在设置文件名称时,文件名称中包含了中文的话,那么需要使用MimeUitlity类来给中文编码:
  74. //imagepart.setFileName(MimeUtility.encodeText("中文.jpg"));
  75. //设置附件,二进制文件可以用application/octet-stream,Word文档则是application/msword。
  76. FileInputStream fileInputStream = new FileInputStream("email\\src\\main\\resources\\people.jpg");
  77. imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(fileInputStream, "image/jpeg")));
  78. //设置ContentID与HTML的中的<img src="cid:img01">关联
  79. imagepart.setContentID("img1");
  80. //把附件添加到部件集中
  81. parts.addBodyPart(imagepart);
  82. /*
  83. * 3 发送邮件
  84. */
  85. Transport.send(msg);
  86. }
  87. }

2.4 JavaMail收取邮件

我们使用pop3协议收取邮件!

  1. public class ReceiveEmail {
  2. public static void main(String[] args) throws MessagingException {
  3. //POP3主机名
  4. String host = "pop3.163.com";
  5. //设置传输协议
  6. String protocol = "pop3";
  7. //用户账号
  8. String username = "15732631416@163.com";
  9. //密码或者授权码
  10. String password = "NPYRDKGYNSZIRZYO";
  11. /*
  12. * 获取Session
  13. */
  14. Properties props = new Properties();
  15. //协议
  16. props.setProperty("mail.store.protocol", protocol);
  17. //POP3主机名
  18. props.setProperty("mail.pop3.host", host);
  19. props.setProperty("mail.smtp.auth", "true");
  20. Session session = Session.getInstance(props);
  21. session.setDebug(true);
  22. /*
  23. * 获取Store,一个Store对象表示整个邮箱的存储
  24. *
  25. */
  26. URLName urlName = new URLName(protocol, host, 110, null, username, password);
  27. Store store = session.getStore(urlName);
  28. //连接邮件服务器
  29. store.connect();
  30. //要收取邮件,我们需要通过Store访问指定的Folder(文件夹),通常是INBOX表示收件箱
  31. //获取邮箱的邮件夹,通过pop3协议获取某个邮件夹的名称只能为inbox,不区分大小写
  32. Folder folder = store.getFolder("INBOX");
  33. //打开邮箱方式(邮件访问权限),这里的只读权限
  34. folder.open(Folder.READ_ONLY);
  35. //打印邮件总数/新邮件数量/未读数量/已删除数量:
  36. System.out.println("Total messages: " + folder.getMessageCount());
  37. System.out.println("New messages: " + folder.getNewMessageCount());
  38. System.out.println("Unread messages: " + folder.getUnreadMessageCount());
  39. System.out.println("Deleted messages: " + folder.getDeletedMessageCount());
  40. // 获得邮件夹Folder内的所有邮件Message对象,一个Message代表一个邮件
  41. Message[] messages = folder.getMessages();
  42. for (Message message : messages) {
  43. /*解析邮件*/
  44. //获取主题
  45. String subject = message.getSubject();
  46. System.out.println(subject);
  47. //解析其他内容
  48. //………………
  49. }
  50. //传入true表示删除操作会同步到服务器上(即删除服务器收件箱的邮件),无参方法默认传递true
  51. folder.close();
  52. store.close();
  53. }
  54. }

2.5 相关异常

  1. Exception in thread “main” com.sun.mail.smtp.SMTPSendFailedException: 554 DT:SPM

    1. 一般是被邮件服务器识别为垃圾邮件,可以换个复杂点的主题和内容,或者换台主机发送。这很麻烦,比如在运行上面的案例时就有可能抛出这样的异常!
  2. Exception in thread “main” javax.mail.AuthenticationFailedException: 535 Error: authentication failed

    1. PasswordAuthentication中的用户登陆信息错误,可能是密码或者授权码错误。
  3. Exception in thread “main” com.sun.mail.smtp.SMTPSendFailedException: 553 Mail from must equal authorized user

    1. 如果用户信息和发件人信息不一致

3 总结

本次我们学习了使用JavaMail的API简单的收发邮件的过程,电子邮件的收发需要使用道SMTP和POP3协议。在实际开发中,这样的底层API我们用的比较少,因为代码编写很麻烦,因此本文了解就行了。

在实际项目开发中,常常使用Spring框架为我们提供的更高级的发送邮件的API。

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

发表评论

表情:
评论列表 (有 0 条评论,990人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java收发邮件

    第一步对邮箱进行配置,以QQ邮箱为例,先在邮箱设置里面选择账户 ![2020020709110014.png][] 然后开启服务,这一步需要短信验证,通过之后会生成授权码,