日常工作生活中少不了和邮件打交道,比如我们会用邮件进行信息交流,向上级汇报日常工作;再比如大家熟悉的某个WEB系统注册阶段,通常会有一个功能,点击发送到目标邮箱的链接完成账户激活。本博客主要是介绍在java环境下如何发送邮件
开始之前先简单介绍一下与邮件相关的一些协议
SMTP 协议
- SMTP 的全称是 Simple Mail Transfer Protocol,即简单邮件传输协议,它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式
- SMTP 协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。
- SMTP 服务器就是遵循SMTP协议的发送邮件服务器
- SMTP 认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器,这就使得那些垃圾邮件的散播者无可乘之机
- 增加 SMTP 认证的目的是为了使用户避免受到垃圾邮件的侵扰
- 实际上,SMTP 已经是E-mail传输的标准
- SMTP 规范(RFC 821)规定,每一行都要以\r\n 来结尾
POP 协议
- POP3(Post Office Protocol 3)即邮局协议的第3个版本,是因特网电子邮件的第一个离线协议标准
- POP邮局协议负责从邮件服务器中检索电子邮件
- 它要求邮件服务器完成下面几种任务之一
- 从邮件服务器中检索邮件并从服务器中删除这个邮件
- 从邮件服务器中检索邮件但不删除它
- 不检索邮件,只是询问是否有新邮件到达
- POP协议支持多用户互联网邮件扩展,后者允许用户在电子邮件上附带二进制文件,如文字处理文件和电子表格文件等,实际上这样就可以传输任何格式的文件了,包括图片和声音文件等
- 在用户阅读邮件时,POP命令所有的邮件信息立即下载到用户的计算机上,不在服务器上保留
IMAP 协议
- 互联网信息访问协议(IMAP)是一种优于POP的新协议
- 和POP一样,IMAP也能下载邮件、从服务器中删除邮件或询问是否有新邮件,但IMAP克服了POP的一些缺点
- 它可以决定客户机请求邮件服务器提交所收到邮件的方式,请求邮件服务器只下载所选中的邮件而不是全部邮件
- 客户机可先阅读邮件信息的标题和发送者的名字再决定是否下载这个邮件
- 通过用户的客户机电子邮件程序,IMAP可让用户在服务器上创建并管理邮件文件夹或邮箱、删除邮件、查询某封信的一部分或全部内容,完成所有这些工作时都不需要把邮件从服务器下载到用户的个人计算机上。
电子邮件发送和接收的过程如下图所示:
图示的六个步骤分别进行如下的说明:
①、用户A的电子邮箱为:xx@qq.com,通过邮件客户端软件写好一封邮件,交到QQ的邮件服务器,这一步使用的协议是SMTP,对应图示的①;
②、QQ邮箱会根据用户A发送的邮件进行解析,也就是根据收件地址判断是否是自己管辖的账户,如果收件地址也是QQ邮箱,那么会直接存放到自己的存储空间。这里我们假设收件地址不是QQ邮箱,而是163邮箱,那么QQ邮箱就会将邮件转发到163邮箱服务器,转发使用的协议也是SMTP,对应图示的②;
③、163邮箱服务器接收到QQ邮箱转发过来的邮件,也会判断收件地址是否是自己,发现是自己的账户,那么就会将QQ邮箱转发过来的邮件存放到自己的内部存储空间,对应图示的③;
④、用户A将邮件发送了之后,就会通知用户B去指定的邮箱收取邮件。用户B会通过邮件客户端软件先向163邮箱服务器请求,要求收取自己的邮件,对应图示的④;
⑤、163邮箱服务器收到用户B的请求后,会从自己的存储空间中取出B未收取的邮件,对应图示⑤;
⑥、163邮箱服务器取出用户B未收取的邮件后,将邮件发给用户B,对应图示的⑥;最后三步用户B收取邮件的过程,使用的协议是POP3;
通过以上邮件收发过程可以知道,如果只是要发送邮件的话我们只需要与SMTP打交道。
在用java发邮件之前,我们需要对用来发邮件的账户先进行一些设置
第一步:先去你的邮箱设置里面开启POP3/SMTP服务与IMAP/SMTP服务
第二步:设置你自己的授权码(发邮件用的是你的授权码,不是用你邮箱的密码)
开发环境准备
发送邮件的话只需要加入一个jar包即可
1.发送简单文本邮件
public void testJavaMail() throws Exception{
//1.设置邮件的一些信息
Properties props = new Properties();
//发送邮件的服务器地址
props.put("mail.smtp.host", "smtp.163.com");// stmp.qq.com smtp.sina.com
//设置发送邮件使用的传输协议
properties.setProperty("mail.transport.protocol", "smtp");
//并且要设置使用验证:
props.setProperty("mail.smtp.auth", "true");
//使用 STARTTLS安全连接:
props.setProperty("mail.smtp.starttls.enable","true");
// 开启debug模式,能够在控制台看到发送邮件的过程
properties.setProperty("mail.debug", "true");
//2.创建Session对象
Session session =Session.getInstance(props);
//3.创建出MimeMessage,邮件的消息对象
MimeMessage message = new MimeMessage(session);
//4.设置发件人
Address fromAddr = new InternetAddress("xxx@163.com");
message.setFrom(fromAddr);
//5.设置收件人
Address toAddr = new InternetAddress("XXX@qq.com");
message.setRecipient(RecipientType.TO, toAddr);
//6.设置邮件的主题
message.setSubject("JavaEmail测试");
//7.设置邮件的正文
message.setText("邮件测试,你收到了吗");
//8.得到传输对象
Transport transport = session.getTransport();
//连接SMTP服务器
//第一个参数是你用来发送邮件的邮箱的SMTP服务器地址,第二个是你的邮箱地址,第三个是授权码
transport.connect("smtp.163.com", "XXXXX@163.com", "SHOUQUANMA");
//设置需要发送的信息以及收件人地址,第二个参数是个Address数组:Address[]
transport.sendMessage(message, message.getAllRecipients());
transport.close();
System.out.println("关闭");
}
这样一封简单的文本邮件就发送出去了,
当然我们不单单可以发送文本邮件,还可以发送带有图片以及附件的图片。
2.发送带图片的邮件
如果你需要发送带有附件或图片的邮件,只需要在message对象里面做一些修改即可。
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("13640139147@163.com"));
message.setRecipient(RecipientType.TO, new InternetAddress("xxx@qq.com"));
message.setSubject("这是一个带图片的邮件");
message.setSentDate(Calendar.getInstance().getTime());
MimeBodyPart txt = new MimeBodyPart();
//要显示图片就用content不要用text datahandler指向的资源 要加上cid:前缀 不然不显示
txt.setContent("这是一张图片\n<img src='cid:c.png' />","text/html;charset=UTF-8");
MimeBodyPart img = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("d:\\00.png"));
img.setDataHandler(dh);
img.setContentID("c.png");
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(txt);
multipart.addBodyPart(img);
multipart.setSubType("related");
message.setContent(multipart);
发送带图片的邮件需要使用<img />标签,并且标签内的src属性需要以cid:开头,后面跟随的是MimeBodyPart对象的ContentID,因为图片放在DataHandler里面,DataHandler放在MimeBodyPart里面。结构如下图:
然后使用MimeMultipart的addBodyPart()方法将存放文本的MimeBodyPart与存放图片的MimeBodyPart放入MimeMultipart对象中,并设置他们的子类型化为关联的multipart.setSubType("related"),这样图片与文本就关联起来了。
最后将MimeMultipart对象设置文Message对象的content,一封带图片的邮件就完成了。
3.发送带附件的邮件
发送带附件邮件的原理也是一样的,图片其实本质上就是一种附件
MimeBodyPart attach = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("d:\\00.png"));
attach.setDataHandler(dh);
//设置附件名字
attach.setFileName(dh.getName());
然后在multipart中将文本内容与附件的关系设置为mixed混合的即可
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(text);
multipart.addBodyPart(attach);
multipart.setSubType("mixed");