目录
一、关于电子邮件
电子邮件
传输协议
SMTP协议
POP3协议
邮件收发原理
二、发送纯文本邮件
二、发送带图片和附件的邮件
一、关于电子邮件
电子邮件
要在网络上实现邮件功能,必须要有专门的邮件服务器。
这些邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中。
SMTP服务器地址:一般是 smtp.xxx.com,比如163邮箱是smtp.163.com,qq邮箱是smtp.qq.com。
使用Java发送邮件,还需要设置使用账号开启相关服务,拿到授权码:
传输协议
SMTP协议
发送邮件:
我们通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。
POP3协议
接收邮件:
我们通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)。
邮件收发原理
1、首先通过smtp协议连接到Smtp服务器,然后发送一封邮件给网易的邮件服务器
2、网易分析发现需要去QQ的邮件服务器,通过smtp协议将邮件转投给QQ的Smtp服务器
3、QQ将接收到的邮件存储在545646733@qq.com这个邮件账号的空间中
4、再通过Pop3协议连接到Pop3服务器收取邮件
5、从545646733@qq.com这个邮件账号的空间中取出邮件
6、Pop3服务器将取出来的邮件送出去
二、发送纯文本邮件
使用Java发送邮件,首先需要引入相关的依赖:
<dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.4</version>
</dependency>
JavaMail 是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等。我们在使用JavaMail API 编写邮件时,无须考虑邮件的底层实现细节,只要调用JavaMail 开发包中相应的API类就可以了。
Java发送邮件三步骤:
1、创建包含连接邮件服务器授权信息的Session对象
(1)编写抽象类Authenticator的实现子类,在子类中覆盖父类的getPasswordAuthentication方法,并返回封装用户名和密码的PasswordAuthentication对象;
(2) 调用Session.getInstance(Properties, Authenticator)方法获得Session类的实例对象,并把Authenticator对象注册到Session对象中。
2、创建代表邮件内容的Message对象
使用Session对象创建代表邮件消息内容的Message对象
3、通过Transport,发送Message
方式一:调用Transport.send静态方法发送Message对象中的邮件消息内容。send方法将从Message对象中获得Session对象的引用,然后将调用Session对象中注册的Authenticator对象从中获取认证信息后传递给邮件服务器。
方式二:使用Transport的connect方法连接邮件服务器,然后使用sendMessage发送发送邮件;最后调用close方法关闭邮件服务器的连接。(不推荐,麻烦)
代码示例:
public class SendEmail {public static void main(String[] args) throws MessagingException, GeneralSecurityException {Properties props = new Properties();// 设置邮件服务器 QQ:smtp.qq.com 163:smtp.163.comprops.setProperty("mail.smtp.host", "smtp.qq.com");// 设置是否需要验证用户名props.setProperty("mail.smtp.auth", "true");// 如果是QQ邮箱,还要设置SSL加密,加上以下代码即可MailSSLSocketFactory sf = new MailSSLSocketFactory();sf.setTrustAllHosts(true);props.put("mail.smtp.ssl.enable", "true");props.put("mail.smtp.ssl.socketFactory", sf);/*** 发送邮件三步骤*/// 1、创建定义整个应用程序所需的环境信息的Session 对象Session session = Session.getInstance(props, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {// 发件人邮件用户名、授权码return new PasswordAuthentication("xxx@qq.com", "xxx");}});// 开启Session的debug模式,这样就可以查看到程序发送Email的运行状态session.setDebug(true);// 2、创建邮件对象MimeMessage message = new MimeMessage(session);// 发件人message.setFrom(new InternetAddress("xxx@qq.com"));// 指定收件人message.setRecipients(Message.RecipientType.TO, "xxx@126.com");// 指定抄送人message.setRecipients(Message.RecipientType.CC, "xxx@qq.com");// 设置邮件主题message.setSubject("Announcement");// 设置邮件内容message.setText("let's go party!");// 设置发送时间message.setSentDate(new Date());// 3、发送邮件,调用Transport.send静态方法发送Message对象中的邮件消息内容Transport.send(message);}
}
二、发送带图片和附件的邮件
先认识两个类一个名词:
MIME(多用途互联网邮件扩展类型)
MiniMultipart类
MiniMultipart类是一个容器类,包含MimeBodyPart类型的对象,Javamail邮件Multipart支持同时发text和html混合消息。
常见的multipart类型有三种:
multipart/mixed:附件。
multipart/related:内嵌资源。
multipart/alternative:纯文本与超文本共存。
如果在邮件中要添加附件,必须定义multipart/mixed段;如果存在内嵌资源,至少要定义multipart/related段;如果纯文本与超文本共存,至少要定义multipart/alternative段。什么是“至少”?举个例子说,如果只有纯文本与超文本正文,那么在邮件头中将类型扩大化,定义为multipart/related,甚至multipart/mixed,都是允许的。
MimeMultipart是Multipart的实现类,默认类别是mixed。其他multipart子类型如:related和alternative可以通过new MimeMultipart(“alternative”)来实现
代码示例:
public class SendEmail {public static void main(String[] args) throws MessagingException, GeneralSecurityException {Properties props = new Properties();// 设置邮件服务器 QQ:smtp.qq.com 163:smtp.163.comprops.setProperty("mail.smtp.host", "smtp.qq.com");// 设置是否需要验证用户名props.setProperty("mail.smtp.auth", "true");// 如果是QQ邮箱,还要设置SSL加密,加上以下代码即可MailSSLSocketFactory sf = new MailSSLSocketFactory();sf.setTrustAllHosts(true);props.put("mail.smtp.ssl.enable", "true");props.put("mail.smtp.ssl.socketFactory", sf);/*** 发送邮件三步骤*/// 1、创建定义整个应用程序所需的环境信息的Session 对象Session session = Session.getInstance(props, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {// 发件人邮件用户名、授权码return new PasswordAuthentication("xxx@qq.com", "xxx");}});// 开启Session的debug模式,这样就可以查看到程序发送Email的运行状态session.setDebug(true);// 2、创建邮件对象MimeMessage message = new MimeMessage(session);// 发件人message.setFrom(new InternetAddress("xxx@qq.com"));// 指定收件人message.setRecipients(Message.RecipientType.TO, "xxx@126.com");// 指定抄送人message.setRecipients(Message.RecipientType.CC, "xxx@qq.com");// 设置邮件主题message.setSubject("带图片的信息");// 图片MimeBodyPart image = new MimeBodyPart();DataHandler dataHandler = new DataHandler(new FileDataSource("D:\\demofiles\\gougou.jpg"));image.setDataHandler(dataHandler);image.setContentID("gougou");// 图片设置ID// 文本MimeBodyPart text = new MimeBodyPart();text.setContent("这是一封邮件正文带图片<img src='cid:gougou' width='200' height='100'>的邮件", "text/html;charset=UTF-8");// 附件一MimeBodyPart appendix1 = new MimeBodyPart();// 把前一张图片覆盖掉了DataHandler appendixHandler1 = new DataHandler(new FileDataSource("D:\\demofiles\\lang.jpg"));appendix1.setDataHandler(appendixHandler1);appendix1.setFileName("lang.jpg");// 为附件设置名字,不能和内嵌文件重名,否则<img/>会解析出错// 附件二MimeBodyPart appendix2 = new MimeBodyPart();DataHandler appendixHandler2 = new DataHandler(new FileDataSource("D:\\demofiles\\flowers.jpg"));appendix2.setDataHandler(appendixHandler2);appendix2.setFileName("lang.jpg");// 附件和附件的名字可以一样,邮件会自动标号区别// 描述数据关系:文本+图片,捆绑成一个relatedMimeMultipart related = new MimeMultipart("related");related.addBodyPart(text);related.addBodyPart(image);// 将拼装好的正文内容捆绑成一个主体MimeBodyPart contentText = new MimeBodyPart();contentText.setContent(related);// 描述数据关系: 附件+(文本+图片)MimeMultipart allFile =new MimeMultipart("mixed");allFile.addBodyPart(appendix1); // 附件一allFile.addBodyPart(appendix2); // 附件二allFile.addBodyPart(contentText);// 正文内容// allFile.addBodyPart(image); // 不能再设置image为附件,无效// allFile.addBodyPart(appendix2); // 附件同文件可以重复// 封装Message消息,保存修改message.setContent(allFile);message.saveChanges();// 设置发送时间message.setSentDate(new Date());// 3、发送邮件,调用Transport.send静态方法发送Message对象中的邮件消息内容Transport.send(message);}
}
代码中,<img/>标签用到了cid,那什么是cid呢?
一封邮件由邮件头(Headers)和邮件体组成的,邮件头中包括了各种属性,其中就有cid,即Content-Id,下图是Java邮件开发详解中对Content-id的解释(张孝祥版PDF)
这个cid跟这封邮件的内嵌资源一一对应,这个cid主要用来替换你下载到本地的资源文件比如gif表情,然后将src中的路径换成本地路径才能正常显示,这个没有附件容易理解,其实可以这样理解,他也是附件,就是你要先下载到本地,替换完之后才能正常的展示到用户面前,多了个下载的过程,而附件可以直接展示,点击某个附件再调用下载的过程。