廖雪峰Java13网络编程-2Email编程-1发送email
1.邮件发送
1.1传统邮件发送:
- 传统的邮件是通过邮局投递,从一个邮局到另一个邮局,最终到达用户的邮箱。
1.2电子邮件发送:
- 与传统邮件类似,它是从用户电脑的邮件软件(如outlook)发送到邮件服务器上,然后经过若干个邮件服务器的中转,到达对方邮件服务器上,收件方就可以用软件或浏览器来接收邮件。
- MUA(邮件软件,Mail User Agent)——>MTA(邮件服务器,Mail Transfer Agent)——>MTA——>MDA(邮件投递代理,Mail Delivery Agent)<——MUA
- 邮件一半到达MDA就不再动了,等收件人通过MUA或浏览器查看邮件即可
- 从MUA发送到MTA使用的协议就是SMTP协议
1.3 SMTP协议:发送电子邮件的协议
- Simple Mail Transport protocol:SMTP是一个建立在TCP之上的协议。
- 标准端口:25
- 加密端口:465/587。如果某个会话需要被加密的话,使用加密端口465/587
2 如何发送EMail:
- 使用Java Mail API
- 无需关心SMTP协议原理。
2.1 使用Java Mail API有三个部分
# 创建session
Session session = Session.getInstance(props,new Authenticator(){...});
# 创建message对象
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("from@email.com")); //发件人
message.setRecipient(Message.RecipientType.TO, new IntenetAddress("to@email.com")); //收件人
message.setSubject("RE:how to use JavaEmail","UTF-8"); //邮件主题
message.setText("blablabla...","UTF-8"); //邮件正文
# 发送邮件
Transport.send(message);
示例代码
package com.csj2018;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class SendQQMailUtil {
public static void main(String[] args) throws AddressException,MessagingException {
Properties properties = new Properties();
properties.put("mail.transport.protocol", "smtp");// 连接协议
properties.put("mail.smtp.host", "smtp.qq.com");// 主机名 网易替换为"smtp.126.com"
properties.put("mail.smtp.port", 465);// 端口号
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.ssl.enable", "true");// 设置是否使用ssl安全连接 ---一般都使用
// properties.put("mail.debug", "true");// 设置是否显示debug信息 true 会在控制台显示相关信息,同session.setDebug(true);
// 得到回话对象
Session session = Session.getInstance(properties);
session.setDebug(true);
// 获取邮件对象
Message message = new MimeMessage(session);
// 设置发件人邮箱地址
message.setFrom(new InternetAddress("123456789@qq.com"));
// 设置收件人邮箱地址,多个收件人
message.setRecipients(Message.RecipientType.TO, new InternetAddress[]{new InternetAddress("123456789@qq.com"),new InternetAddress("1234567890@qq.com")});
//message.setRecipient(Message.RecipientType.TO, new InternetAddress("xxx@qq.com"));//一个收件人
// 设置邮件标题
message.setSubject("xmqtest");
// 设置邮件内容
message.setText("邮件内容邮件内容邮件内容xmqtest");
// 得到邮差对象
Transport transport = session.getTransport();
// 连接自己的邮箱账户
transport.connect("123456789@qq.com", "abcdefg");// 密码为QQ邮箱开通的stmp服务后得到的客户端授权码
// 发送邮件
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
}
2.2 新建maven工程
pom.xml导入依赖
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
注意:不要导错依赖。详细请参考
<!-- https://mvnrepository.com/artifact/javax.mail/javax.mail-api -->
<!--导入javax.mail-api,运行时会提示Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/MailLogger
-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.2</version>
</dependency>
2.3 发送一封文本邮件
package com.email;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.MessageDigest;
import java.util.Properties;
public class SendMail {
final String smtpHost;
final String username;
final String password;
final boolean debug;
public SendMail(String smtpHost,String username,String password){
this.smtpHost = smtpHost;
this.username = username;
this.password = password;
this.debug = true;
}
public static void main(String[] args) throws Exception{
SendMail sender = new SendMail("smtp.qq.com","123456789@qq.com","abcdefg");
Session session = sender.createSSLSession();
Message message = createTextMessage(session,"123456789@qq.com","123456789@126.com","标题吗","Hello,这是一封Javamail测试邮件");
Transport.send(message);
}
//创建一个加密的session对象
private Session createSSLSession(){
Properties props = new Properties();
props.put("mail.transport.protocol","smtp");
props.put("mail.smtp.host",this.smtpHost);//SMTP主机名
props.put("mail.smtp.port",465);//主机端口号
props.put("mail.smtp.auth","true");//是否需要用户认证
//启动SSL
props.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.port","465");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(SendMail.this.username,SendMail.this.password);
}
});
session.setDebug(this.debug);//显示调试信息
return session;
}
private static Message createTextMessage(Session session,String from,String to,String subject,String body) throws MessagingException {
MimeMessage message= new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO,new InternetAddress(to));
message.setSubject(subject,"UTF-8");
message.setText(body,"UTF-8");
return message;
}
}
2.4发送一个HTML格式的邮件
package com.email;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class SendMailWithHtml {
public static void main(String[] args) throws Exception{
SendMail sendMail = new SendMail("smtp.qq.com","123456789@qq.com","abcdefg");
Session session = sendMail.createSSLSession();
Message message = createHtmlMessage(session,"123456789@qq.com","123456789@126.com","这是一封html的邮件","\n" +
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
"\n" +
"<head>\n" +
"\n" +
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" +
"<meta http-equiv=\"Cache-Control\" content=\"no-transform\" />\n" +
"<title>剧烈咳嗽就是肺癌?肺癌的这些症状也不可忽视 - 家庭医生在线肿瘤频道</title>\n" +
"<meta name=\"keywords\" content=\"剧烈咳嗽,肺癌,肺癌的症状\" />\n" +
"<meta name=\"description\" content=\"肺癌,一个发病率极其高的癌症,由于目前环境污染日渐严重,导致越来越多的人肺部受到感染而出现病变,导致肺癌的出现,生活中有很多因为肺癌而丧失性命的人。也正是因为如此让很多人对于肺癌都比较重视,对于肺癌也有做相关的了解,而大多数人因为过于谨慎,在身体出现一些成风吹草动的时候就认为是肺癌,特别是在出现剧烈咳嗽的时候,其实出现剧烈咳嗽也并不完全是肺癌发生。\" />\n" +
"<script type=\"text/javascript\">\n" +
"CUSTOMER.setCus([\"channel:cancer\",\"level:page\"]);\n" +
"</script>\n" +
"</head>\n" +
"<body>\n" +
"\t<div class=\"article-titile\">\n" +
"\t\t<h1>剧烈咳嗽就是肺癌?肺癌的这些症状也不可忽视</h1></div>\n" +
"<!--头部模块开始--> \n" +
"<div id=\"viewContent\" class=\"viewContent\"> <p style=\"text-indent:2em;text-align:left;\">肺癌,一个发病率极其高的,由于目前环境污染日渐严重,导致越来越多的人肺部受到而出现病变,导致肺癌的出现,生活中有很多因为肺癌而丧失性命的人。也正是因为如此让很多人对于肺癌都比较重视,对于肺癌也有做相关的了解,而大多数人因为过于谨慎,在身体出现一些成风吹草动的时候就认为是肺癌,特别是在出现剧烈咳嗽的时候,其实出现剧烈咳嗽也并不完全是肺癌发生。</p>\n" +
"\t\t\t</div>\n" +
"</body>\n" +
"</html>");
Transport.send(message);
}
static Message createHtmlMessage(Session session,String from,String to,String subject,String body) throws MessagingException{
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO,new InternetAddress(to));
message.setSubject(subject,"UTF-8");
message.setText(body,"UTF-8","html");
return message;
}
}
### 2.5发送带附件的邮件
```#java
package com.email;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.;
public class SendMailWithAttachment {
public static void main(String[] args) throws Exception{
SendMail sender = new SendMail("smtp.qq.com","123456678@qq.com","abcdefghjik");
Session session = sender.createSSLSession();
//创建一个带附件的邮件
Message message = createMessageWithAttachment(session,"123456678@qq.com","红米note5图片","为什么成功了","/src/main/resources/1.jpg","123456789@qq.com","987654321@qq.com","123456789@126.com");
Transport.send(message);
File f = new File(".");
System.out.println(f.getCanonicalFile());
File nf = new File(f.getCanonicalFile()+"/src/main/resources/1.jpg");
if(nf.exists()){
System.out.println(nf+"存在");
}else{
System.out.println(nf+"不存在");
}
}
static Message createMessageWithAttachment(Session session, String from, String subject,String body, String filename, String... to) throws MessagingException,IOException {
//本质上还是一个MimeMessage对象,但不能通过setText设置正文,需要使用MimeMultipart
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
for(String s:to){
message.setRecipient(Message.RecipientType.TO,new InternetAddress(s));
}
message.setSubject(subject);
//通过Multipart将内容分为2部分
Multipart multipart = new MimeMultipart();
//text
BodyPart textpart = new MimeBodyPart();
textpart.setContent(body,"text/html;charset=utf-8");//body表示邮件正文
multipart.addBodyPart(textpart);
//再次创建一个MimeBodyPart上传附件
BodyPart imagePart = new MimeBodyPart();
imagePart.setFileName(filename);
DataHandler dh1 = new DataHandler(new FileDataSource(new File(".").getCanonicalPath()+filename));
imagePart.setDataHandler(dh1);//如何获取附件的数据
multipart.addBodyPart(imagePart);
message.setContent(multipart);
return message;
}
}
<h1 style="color:blue">使用输入流发送附件</h1>
<p style="color:red">确保图片在resource目录下</p>
```#java
package com.email;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class SendMailWithAttachment {
public static void main(String[] args) throws Exception{
SendMail sender = new SendMail("smtp.qq.com","123456789@qq.com","abcdefghjkik");
Session session = sender.createSSLSession();
//创建一个输入流
try(InputStream input = SendMailWithAttachment.class.getResourceAsStream("/1.jpg")){
//创建一个带附件的邮件
Message message = createMessageWithAttachment(session,"123456789@qq.com","红米note5图片","为什么成功了","1.jpg",input,"123456789@qq.com","987654321@qq.com","123456789@126.com");
Transport.send(message);
}
}
static Message createMessageWithAttachment(Session session, String from, String subject,String body, String filename,InputStream input, String... to) throws MessagingException,IOException {
//本质上还是一个MimeMessage对象,但不能通过setText设置正文,需要使用MimeMultipart
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
for(String s:to){
message.setRecipient(Message.RecipientType.TO,new InternetAddress(s));
}
message.setSubject(subject);
//通过Multipart将内容分为2部分
Multipart multipart = new MimeMultipart();
//text
BodyPart textpart = new MimeBodyPart();
textpart.setContent(body,"text/html;charset=utf-8");//body表示邮件正文
multipart.addBodyPart(textpart);
//再次创建一个MimeBodyPart上传附件
BodyPart imagePart = new MimeBodyPart();
imagePart.setFileName(filename);
imagePart.setDataHandler(new DataHandler(new ByteArrayDataSource(input,"Application/octet-stream")));
multipart.addBodyPart(imagePart);
message.setContent(multipart);
return message;
}
}
2.6如何把附件嵌入到正文中
package com.csj2018;
import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import java.io.InputStream;
public class SendMailWithInnerImage {
public static void main(String[] args) throws Exception{
SendMail sender = new SendMail("smtp.qq.com", "815379479@qq.com", "oovtbkpfvfzobdag");
Session session = sender.createSSLSession();
try(InputStream input = SendMailWithInnerImage.class.getResourceAsStream("/RedmiNote5-1.png")){
Message message = createMessageWithInnerImage(session,"815379479@qq.com","chenshanju01@126.com","带图片测试","<h1><hello/h1><p><img src=\"cid:img01\" ></p><p>这是一封带图片的测试邮件</p>","1.png",input);
Transport.send(message);
}
}
static Message createMessageWithInnerImage(Session session, String from, String to, String subject, String body, String filename, InputStream input) throws Exception{
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO,new InternetAddress(to));
message.setSubject(subject,"UTF-8");
Multipart multipart = new MimeMultipart();
BodyPart textpart = new MimeBodyPart();
textpart.setContent(body,"text/html;charset=utf-8");
multipart.addBodyPart(textpart);
BodyPart imagepart = new MimeBodyPart();
imagepart.setFileName(filename);
imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(input,"application/x-png")));
//对一个图片内容设置Content-ID,就可以在邮件中引用它,引用方式是<img src="cid:img01">
imagepart.setHeader("Content-ID","<img01>");
multipart.addBodyPart(imagepart);
message.setContent(multipart);
return message;
}
}
content-type类型对应表:http://tool.oschina.net/commons/
3.总结
使用JavaMail API发送邮件本质上是一个MUA软件,类似outlook
Java发送Email:
- 用Maven引入javamail依赖
- 确定SMTP服务器信息:域名/端口/使用明文/SSL/TLS
- 调用相关API发送Email(无需关心底层TCP Socket连接)
- 设置debug模式可以查看通信详细内容