我们首先了解一下传统的邮件是如何进行发送的,首先把邮件发送到当地的邮局,当地的邮局又把邮件发送给目的地附近的邮局,最后目的地附近的邮局把邮件发送到目的地。
其实Email的发送方式也是类似,我们把类似Outlook 这样的邮件软件称为MUA : Mail User Agent,意思是给用户服务的邮件代理 ;邮件服务器则称为MTA : Mail Transfer Agent , 意思是邮件中转的代理;最终到达的邮件服务器称为MDA : Mail Delivery Agent ,意思是邮件到达的代理。电子邮件一 旦到达MDA ,就不再动了。实际上,电子邮件通常就存储在MDA服务器的硬盘上,然后等收件人通过软件或者登陆浏览器查看邮件。
邮件协议
MTA和MDA这样的服务器软件通常是现成的,我们通常不会关心这些邮件服务器的内部是如何运行的。更多的需求场景,是需要发送邮件。例如:促销商品邮件、验证码邮件、消息通知邮件等。常见的邮件协议有: POP3、SMTP、IMAP。
POP3
POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。它是因特网电子邮件的第一个离线协议标准, POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。
SMTP
SMTP的全称是“Simple Mail Transfer Protocol”, 即简单邮件传输协议。它是一-组用于从源地址到目 的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件时找到下-一个目的地。SMTP 服务器就是遵循SMTP协议的发送邮件服务器。
SMTP认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录SMTP服务器,这就使得那些垃圾邮件的散播者无可乘之机。增加SMTP认证的目的是为了使用户避免受到垃圾邮件的侵扰。
IMAP
IMAP全称是Internet Mail Access Protocol ,即交互式邮件存取协议,它是跟POP3类似邮件访问标准协议之一。不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。
相关协议的端口号
126邮件服务器
所以,当我们关心的是如何实现邮件发送,其实就是编写-个MUA的软件,把邮件发送到MTA上。MUA 到MTA发送邮件的协议就是SMTP协议,它是Simple Mail Transport Protocol 的缩写,使用标准端口25 ,也可以使用加密端口465或587。SMTP 协议是一一个建立在TCP之上的协议,任何程序发送邮件都必须遵守SMTP 协议。使用Java程序发送邮件时,我们无需关心SMTP 协议的底层原理,只需要使用JavaMail 这个标准API就可以直接发送邮件。
例:实现从网易邮箱发送邮件到QQ邮箱
首先定义一个creatSession类来创建Session对象,代码如下:
// 创建Session
public static Session creatSession() {
String smtp = "smtp.126.com";
String userName = "dhz799144872@126.com";
String passWord = "INLYP***IBIKFIYI";
// SMTP服务器连接信息
Properties properties = new Properties();
properties.put("mail.smtp.host", smtp);// SMTP主机名
properties.put("mail.smtp.port", "25");// 主机端口号
properties.put("mail.smtp.auth", "true");// 是否需要用户认证
properties.put("mail.smtp.starttls.enable", "true");// 启用TLS加密
// 创建Session
// 参数1:SMTP服务器的连接信息
// 参数2:用户认证对象(Authenticator接口的匿名实现类)
Session session = Session.getInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, passWord);
}
});
// 开启调试模式
session.setDebug(true);
return session;
}
通过Session对象(封装着网易邮箱信息)向QQ邮箱发送邮件,代码如下:
try {
//1.创建Session会话
//通过自己定义的JavaMailUtils工具包创建Session对象
Session session = JavaMailUtils.creatSession();
//2.创建邮件对象(Message抽象类的子类对象)
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("dhz799144872@126.com"));
//RecipientType后面的常量
//TO:主要收件人
//CC:抄送人
msg.setRecipient(RecipientType.TO, new InternetAddress("1516943397@qq.com"));
msg.setSubject("这是一封离别信","utf-8");
//邮件正文中包含
msg.setText("写下我们离开的原因。","utf-8","html");
//3.发送邮件
Transport.send(msg);
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
发送Email附件
要在电子邮件中携带附件,我们就不能直接调用message.setText()方法,而是要构造一个Multipart对象:
// 创建MimeMessage邮件信息对象
// ...略
// 创建Multipart复合对象
Multipart multipart = new MimeMultipart();
// 添加text:
BodyPart textpart = new MimeBodyPart();
textpart.setContent(body, "text/html;charset=utf-8");
multipart.addBodyPart(textpart);
// 添加image:
BodyPart imagepart = new MimeBodyPart();
imagepart.setFileName(附件名称);
imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(文件流字节数组, "application/octet-stream")));
multipart.addBodyPart(imagepart);
// 设置邮件内容为multipart:
message.setContent(multipart);
一个Multipart 对象可以添加若千个BodyPart ,其中第一个BodyPart 文本,即邮件正文,后面的BodyPart 是附件。BodyPart 依靠setContent() 决定添加的内容,如果添加文本,用setContent("...", "text/plain; charset=utf-8")添加纯文本,或者用setContent("...","text/html ;charset=utf-8")添加HTML文本。如果添加附件,需要设置文件名(不-定和真实文件名-致) ,并且添加一个DataHandler() ,传入文件的MIME类型。二进制文件可以用application/octet-stream ,Word文档则是application/ msword最后,通过setContent()把Multipart 添加到Message中,即可发送。
例:发送邮件并且把附件图片内容显示在内容部分
public static void main(String[] args) {
try {
Session session = JavaMailUtils.creatSession();
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("接受的邮箱.com"));
msg.setRecipient(RecipientType.TO, new InternetAddress("发送的邮箱.com"));
msg.setRecipients(RecipientType.CC, new InternetAddress[]{
new InternetAddress("抄送的邮箱.com"),
new InternetAddress("抄送的邮箱.com"),
new InternetAddress("抄送的邮箱.com")
});
msg.setSubject("这是一封水母图片","utf-8");
//邮件正文部分
BodyPart textBodyPart = new MimeBodyPart();
StringBuilder sb = new StringBuilder();
sb.append("<h1>水母</h1>");
sb.append("<img src=\"cid:shuimu\" />");
textBodyPart.setContent(sb.toString(), "text/html;charset=utf-8");
//邮件附件部分
BodyPart imageBodyPart = new MimeBodyPart();
imageBodyPart.setFileName("shuimu.jpg");
imageBodyPart.setDataHandler(new DataHandler(new ByteArrayDataSource(Files.readAllBytes(Paths.get("D:\\jpg\\1657264168667.jpg")),"application/octet-stream")));
imageBodyPart.setHeader("Content-ID", "<shuimu>");
//组合正文+附件
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(textBodyPart);
multipart.addBodyPart(imageBodyPart);
//设置邮件内容
msg.setContent(multipart);
Transport.send(msg);
} catch (MessagingException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}