简介
1.本文只针对基础代码解析整理,原理不想过多解释
2.写这篇博客是为了理清思路
3.本文的测试对象为qq邮箱
发送Email
1.发送原理
发送方发送到邮件服务器,接收方从服务器读取内容的过程
2.协议
1.MUA到MTA发送邮件的协议就是SMTP协议,它是Simple Mail Transport Protocol的缩写
使用标准端口25,也可以使用加密端口465或587
2.SMTP协议是一个建立在TCP之上的协议,任何程序发送邮件都必须遵守SMTP协议
3.MSTP登录信息
QQ邮箱:SMTP服务器是smtp.qq.com,端口是465/587
163邮箱:SMTP服务器是smtp.163.com,端口是465
Gmail邮箱:SMTP服务器是smtp.gmail.com,端口是465/587
4.实例
1、首先是最简单发送纯文本Email实例
//纯文本发送
public class MailService {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
//创建一个配置文件并保存
Properties properties = new Properties();
properties.setProperty("mail.host", "smtp.qq.com"); // SMTP主机名
properties.setProperty("mail.transport.protocol","smtp");
properties.setProperty("mail.smtp.auth","true");// 是否需要用户认证
//QQ存在一个特性设置SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");//开启ssl安全连接
properties.put("mail.smtp.ssl.socketFactory", sf);
//创建一个session对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("发送方邮箱",
"qq邮箱smtp服务授权码");
//在邮箱的设置-》账户-》POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务中获取
}
});
// 设置debug模式便于调试:
session.setDebug(true);
//TODO:构建Message对象
MimeMessage message = new MimeMessage(session);
//设置发送方地址:
try {
message.setFrom(new InternetAddress("发送方地址"));
} catch (MessagingException e) {
e.printStackTrace();
}
// 设置接收方地址:
message.setRecipients(Message.RecipientType.TO,
String.valueOf(new InternetAddress("接收方地址")));
//设置邮件主题
message.setSubject("Hello","UTF-8");
//设置邮件正文
message.setText("hello","UTF-8","html");
//发送
Transport.send(message);
}
}
2、然后是正文有所改变的纯文字HTML代码
//纯文本发送
public class MailService {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
//创建一个配置文件并保存
Properties properties = new Properties();
properties.setProperty("mail.host", "smtp.qq.com"); // SMTP主机名
properties.setProperty("mail.transport.protocol","smtp");
properties.setProperty("mail.smtp.auth","true");// 是否需要用户认证
//QQ存在一个特性设置SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");//开启ssl安全连接
properties.put("mail.smtp.ssl.socketFactory", sf);
//创建一个session对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("发送方邮箱",
"qq邮箱smtp服务授权码");
//在邮箱的设置-》账户-》POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务中获取
}
});
// 设置debug模式便于调试:
session.setDebug(true);
//TODO:构建Message对象
MimeMessage message = new MimeMessage(session);
//设置发送方地址:
try {
message.setFrom(new InternetAddress("发送方地址"));
} catch (MessagingException e) {
e.printStackTrace();
}
// 设置接收方地址:
message.setRecipients(Message.RecipientType.TO,
String.valueOf(new InternetAddress("接收方地址")));
//设置邮件主题
message.setSubject("Hello","UTF-8");
//设置邮件正文
message.setText("<h1>Hello</h1><p>Hi, xxx</p>","UTF-8","html");
//发送
Transport.send(message);
}
}
3、添加附件的Email邮件
//纯文本发送
public class MailService {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
//创建一个配置文件并保存
Properties properties = new Properties();
properties.setProperty("mail.host", "smtp.qq.com"); // SMTP主机名
properties.setProperty("mail.transport.protocol","smtp");
properties.setProperty("mail.smtp.auth","true");// 是否需要用户认证
//QQ存在一个特性设置SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");//开启ssl安全连接
properties.put("mail.smtp.ssl.socketFactory", sf);
//创建一个session对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("发送方邮箱",
"qq邮箱smtp服务授权码");
//在邮箱的设置-》账户-》POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务中获取
}
});
// 设置debug模式便于调试:
session.setDebug(true);
//TODO:构建Message对象
MimeMessage message = new MimeMessage(session);
//设置发送方地址:
try {
message.setFrom(new InternetAddress("发送方地址"));
} catch (MessagingException e) {
e.printStackTrace();
}
// 设置接收方地址:
message.setRecipients(Message.RecipientType.TO,
String.valueOf(new InternetAddress("接收方地址")));
//设置邮件主题
message.setSubject("Hello","UTF-8");
//设置邮件正文
message.setText("hello","UTF-8","html");
//Multipart对象包含若干个bodpart
//bodpart中可以添加各种附件
Multipart multipart = new MimeMultipart();
//TODO:添加text
BodyPart textPart = new MimeBodyPart();
//数据源
DataSource dataSource = new FileDataSource(new
File("D:\\..\\text.txt"));//绝对路径
//数据处理器
DataHandler dataHandler = new DataHandler(dataSource);
//设置第一个附件的数据
textPart.setDataHandler(dataHandler);
textPart.setFileName("text");
multipart.addBodyPart(textPart);
//TODO:添加image
BodyPart imagePart = new MimeBodyPart();
imagePart.setFileName("1.gif");
imagePart.setDataHandler(new DataHandler(new FileDataSource(new
File("D:\\..\\preview.gif"))));//绝对路径
multipart.addBodyPart(imagePart);
//设置邮件内容为multipaet
message.setContent(multipart);
//发送
Transport.send(message);
}
}
测试后邮件正文消失,只包含邮件附件,可能与发送机制有关
4.发送内嵌图片的HTML邮件
注意:如果给一个< img src=“http://example.com/test.jpg”>,这样的外部图片链接通常会被邮件客户端过滤,并提示用户显示图片并不安全。只有内嵌的图片才能正常在邮件中显示
//纯文本发送
public class MailService {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
//创建一个配置文件并保存
Properties properties = new Properties();
properties.setProperty("mail.host", "smtp.qq.com"); // SMTP主机名
properties.setProperty("mail.transport.protocol","smtp");
properties.setProperty("mail.smtp.auth","true");// 是否需要用户认证
//QQ存在一个特性设置SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");//开启ssl安全连接
properties.put("mail.smtp.ssl.socketFactory", sf);
//创建一个session对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("发送方邮箱",
"qq邮箱smtp服务授权码");
//在邮箱的设置-》账户-》POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务中获取
}
});
// 设置debug模式便于调试:
session.setDebug(true);
//Multipart对象包含若干个bodpart
//bodpart中可以添加各种附件
//内嵌图片实际上也是一个附件,即邮件本身也是Multipart
Multipart multipart = new MimeMultipart();
//TODO:构建Message对象
MimeMessage message = new MimeMessage(session);
//设置发送方地址:
try {
message.setFrom(new InternetAddress("发送方地址"));
} catch (MessagingException e) {
e.printStackTrace();
}
// 设置接收方地址:
message.setRecipients(Message.RecipientType.TO,
String.valueOf(new InternetAddress("接收方地址")));
//设置邮件主题
message.setSubject("Hello","UTF-8");
//设置邮件正文
message.setText("<h1>Hello</h1><p>Hi, xxx</p>","UTF-8","html");
//TODO:发送内嵌图片的HTML邮件
Map<String, String> imagesMap = new HashMap<>();
//采用hashmap可以以满足html表达式
imagesMap.put("image","D:\\..\\preview.gif");
// 添加text:
BodyPart textpart = new MimeBodyPart();
textpart.setContent(
"<h1>我老婆发给你了</h1><p><img src=\"cid:image\"></p>",
"text/html;charset=utf-8");
multipart.addBodyPart(textpart);
// 添加image:
BodyPart imagepart = new MimeBodyPart();
imagepart.setFileName("1.gif");
imagepart.setDataHandler(new DataHandler(new FileDataSource(new
File("D:\\..\\preview.gif"))));
// 与HTML的<img src="cid:img01">关联:
imagepart.setHeader("Content-ID", "image");
multipart.addBodyPart(imagepart);
//发送
Transport.send(message);
}
}
5.小结
1.使用JavaMail API发送邮件本质上是一个MUA软件通过SMTP协议发送邮件至MTA服务器
2.打开调试模式可以看到详细的SMTP交互信息
3.某些邮件服务商需要开启SMTP,并需要独立的SMTP登录密码
4.当然老婆是不会给你们看的
接收Email
1.接收Email就是从MTA服务器读取文件的过程
2.因为qq邮箱应该是有新旧两个文件夹或者其它管理机制,从"INBOX"(一般MTA服务器存放邮件的文件夹)读取的
邮件都是之前的邮件,到最近的邮件就没有访问成功过,都是抛出异常,小白我估计是触发了某种机制
3.qq邮箱的发送与接收都需要ssl加密
协议特点
1.使用最广泛的协议是POP3:Post Office Protocol version 3
它是一个建立在TCP连接之上的协议
POP3服务器的标准端口是110,如果整个会话需要加密,那么使用加密端口995
2.另一种接收邮件的协议是IMAP :Internet Mail Access Protocol
它使用标准端口143和加密端口993
IMAP协议在本地的所有操作都会自动同步到服务器上
IMAP可以允许用户在邮件服务器的收件箱中创建文件夹
实例
一看就懂的那种
//接收邮件
public class MailReceive {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
// 准备登录信息:
String host = "pop.qq.com";
int port = 995;
String username = "发送方邮箱";
String password = "授权码";
//创建一个配置文件并保存
Properties properties = new Properties();
properties.setProperty("mail.store.protocol", "pop3");// 协议名称
properties.setProperty("mail.pop3.host",host); // SMTP主机名
properties.setProperty("mail.pop3.port", String.valueOf(port)); // 端口号
properties.setProperty("mail.pop3.auth","true");// 是否需要用户认证
//QQ存在一个特性设置SSL加密,注释掉的和代码也是开启ssl加密的方法
// props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
// props.put("mail.smtp.socketFactory.port", String.valueOf(port));
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.pop3.ssl.enable", "true");//开启ssl安全连接
properties.put("mail.pop3.ssl.socketFactory", sf);
// 连接到Store:
URLName urlName = new URLName("pop3",host,port,"",username,password);
Session session = Session.getInstance(properties,null);
session.setDebug(true);
Store store = new POP3SSLStore(session,urlName);
store.connect();
Folder folder = null;
try {
folder = store.getFolder("INBOX");// 获取收件箱:
folder.open(Folder.READ_WRITE);// 以读写方式打开:
System.out.println("Total messages: " + folder.getMessageCount());
System.out.println("New messages: " + folder.getNewMessageCount());
System.out.println("Unread messages: " + folder.getUnreadMessageCount());
System.out.println("Deleted messages: " + folder.getDeletedMessageCount());
Message[] messages = folder.getMessages();
for (Message message : messages) {
printMessage((MimeMessage) message);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (folder != null) {
try {
folder.close(true);
} catch (MessagingException e) {
e.printStackTrace();
}
}
if (store != null) {
try {
store.close();
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
}
//一封邮件的结构
//大部分商业邮件都是HTML邮件,所以下载的邮件可以将body作为HTML文件查看,但只能加载出图片
//因为传输协议加密内容都有都有==结尾,经过博主测试外面都有外包base64加密
//有一些纯文本甚至可以直接由base64解码查看,所以一定不要让你的授权码外泄
static void printMessage(MimeMessage msg) throws IOException, MessagingException {
System.out.println("--------------------");
System.out.println("Subject: " + MimeUtility.decodeText(msg.getSubject()));
System.out.println("From: " + getFrom(msg));
System.out.println("To: " + getTo(msg));
System.out.println("Sent: " + msg.getSentDate().toString());
System.out.println("Seen: " + msg.getFlags().contains(Flags.Flag.SEEN));
System.out.println("Priority: " + getPriority(msg));
System.out.println("Size: " + msg.getSize() / 1024 + "kb");
System.out.println("Body: " + getBody(msg));
System.out.println("--------------------");
System.out.println();
}
static String getFrom(MimeMessage msg) throws IOException, MessagingException {
Address[] froms = msg.getFrom();
return addressToString(froms[0]);
}
static String getTo(MimeMessage msg) throws MessagingException, IOException {
// 使用 msg.getAllRecipients() 获取所有收件人
Address[] tos = msg.getRecipients(MimeMessage.RecipientType.TO);
List<String> list = new ArrayList<>();
for (Address to : tos) {
list.add(addressToString(to));
}
return String.join(", ", list);
}
static String addressToString(Address addr) throws IOException {
InternetAddress address = (InternetAddress) addr;
String personal = address.getPersonal();
return personal == null ? address.getAddress()
: (MimeUtility.decodeText(personal) + " <" + address.getAddress() + ">");
}
static String getPriority(MimeMessage msg) throws MessagingException {
String priority = "Normal";
String[] headers = msg.getHeader("X-Priority");
if (headers != null) {
String header = headers[0];
if ("1".equals(header) || "high".equalsIgnoreCase(header)) {
priority = "High";
} else if ("5".equals(header) || "low".equalsIgnoreCase(header)) {
priority = "Low";
}
}
return priority;
}
static String getBody(Part part) throws MessagingException, IOException {
if (part.isMimeType("text/*")) {
return part.getContent().toString();
}
if (part.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) part.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
String body = getBody(bodyPart);
if (!body.isEmpty()) {
return body;
}
}
}
return "";
}
}
小结
使用POP3协议时,需要用Maven引入JavaMail依赖,并确定POP3服务器的域名/端口/是否使用SSL等,然后,调用相关API接收Email
大结
1.可以通过线程池实现批量发送邮件
2.发送邮件前要在xml中引入项目,你们需要我可以写个博客做个小结,毕竟有不少坑
3.喜欢就点个赞呗