本篇技术博客整理和总结了JavaMail发送各种不同类型的邮件的案例,以及其中的实现步骤和细节。
目录
一. 概述
使用JAVA程序进行发送邮件,使用的是SMTP协议,它是 Simple Mail Transport Protocol 的缩写,使用标准端口 25 ,也可以使用加密端口 465 或 587 。 SMTP 协议是一个建立在 TCP 之上的协议,任何程序发送邮件都必须遵守 SMTP 协议。使用 Java 程序发送邮件时,我们无需关心 SMTP 协议的底层原理,只需要使用 JavaMail这个标准 API 就可以直接发送邮件。
二. 大致步骤
- 创建session对象,其作用是建立程序与邮件服务商的会话(连接)。
- 创建message对象。
- 设置message对象的内容。
- 发送message。
三. 发送不同类型邮件的案例的实现细节
1. 事前准备
首先我们要准备SMTP的登录信息,本人使用的是163邮箱,下面是不同常用邮件服务商的SMTP信息:
- QQ邮箱:SMTP服务器是 smtp.qq.com ,端口是 465 / 587
- 163邮箱:SMTP服务器是 smtp.163.com ,端口是 465
- Gmail邮箱:SMTP服务器是 smtp.gmail.com ,端口是 465 / 587
准备好登录信息后,需要将相关jar包javax.mail-1.6.2.jar导入到项目中。
然后,我们通过 JavaMail API 连接到 SMTP 服务器上:连接 SMTP 服务器时, 需要准备一个 Properties 对象,填入相关信息。最后创建Session实例时,调用Session.getInstance()方法,第一个参数传入服务器的连接信息properties对象,第二个参数传入Authenticator对象返回用户名和密码用于服务器的认证。当我们获取到 Session 实例后,调用session实例的setDebug()方法打开调试模式可以看到 SMTP 通信的详细内容,便于调试。
这里将session实例的创建过程封装成了一个类中的静态方法,以便于后面session实例的创建。
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
public final class JavaMailUtils {
private JavaMailUtils() {
}
public static Session createSession() {
//邮箱账号信息
String userName = "m18391125066@163.com";// 邮箱发送账号
String password = "SDBHWNAOUZZAXRLH";// 账号授权密码
//SMTP服务器连接信息
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.163.com"); // STMP主机名
props.put("mail.smtp.port", "25"); // 主机端口号
props.put("mail.smtp.auth", "true"); // 是否需要用户认证
props.put("mail.smtp.starttls.enable", "true"); // 启用TLS加密
//创建session对话
// 参数1: smtp服务器连接参数
// 参数2: 账号和密码的授权认证对象
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// TODO Auto-generated method stub
return new PasswordAuthentication(userName, password);
}
});
session.setDebug(true);
return session;
}
}
2. 发送普通文本的邮件
第一步,创建session会话。
使用之前封装好的方法创建session对象。
// 1.创建session对话
Session session = JavaMailUtils.createSession();
第二步,创建邮件对象并设置相关信息。
// 2.创建邮件对象
MimeMessage message = new MimeMessage(session);
message.setSubject("这是来自Gypppppppppppppp的邮件"); // 设置邮件标题
message.setText("hahhhhhhhhhh","utf-8"); // 设置邮件正文
message.setFrom(new InternetAddress("此处为发件人的邮箱")); //设置发件人
message.setRecipient(RecipientType.TO,newInternetAddress("此处为收件人的邮箱")); //设置收件人
第三步,发送邮件。
// 3.发送邮件
Transport.send(message);
发送至qq邮箱:
将调试信息打印到控制台上,我们可以看出: SMTP协议是一个请求-响应协议,客户端总是发送命令,然后等待服务器响应。服务器响应总是以数字开头,后面的信息才是用于调试的文本。 这些响应码已经被定义在SMTP协议中了,查看具体的响应码就可以知道出错原因。
DEBUG: setDebug: JavaMail version 1.6.2
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: need username and password for authentication
DEBUG SMTP: protocolConnect returning false, host=smtp.163.com, user=18018, password=<null>
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.163.com", port 25, isSSL false
220 163.com Anti-spam GT for Coremail System (163com[20141201])
DEBUG SMTP: connected to host "smtp.163.com", port: 25
EHLO LAPTOP-6GE885FP
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN XOAUTH2
250-AUTH=LOGIN PLAIN XOAUTH2
250-coremail 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UFw9LV7UCa0xDrUUUUj
250-STARTTLS
250-ID
250 8BITMIME
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH2"
DEBUG SMTP: Found extension "AUTH=LOGIN", arg "PLAIN XOAUTH2"
DEBUG SMTP: Found extension "coremail", arg "1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UFw9LV7UCa0xDrUUUUj"
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "ID", arg ""
DEBUG SMTP: Found extension "8BITMIME", arg ""
STARTTLS
220 Ready to start TLS
EHLO LAPTOP-6GE885FP
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN XOAUTH2
250-AUTH=LOGIN PLAIN XOAUTH2
250-coremail 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UryxxwZUCa0xDrUUUUj
250-STARTTLS
250-ID
250 8BITMIME
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH2"
DEBUG SMTP: Found extension "AUTH=LOGIN", arg "PLAIN XOAUTH2"
DEBUG SMTP: Found extension "coremail", arg "1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UryxxwZUCa0xDrUUUUj"
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "ID", arg ""
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: protocolConnect login, host=smtp.163.com, user=m18391125066@163.com, password=<non-null>
DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM XOAUTH2
DEBUG SMTP: Using mechanism LOGIN
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN succeeded
DEBUG SMTP: use8bit false
MAIL FROM:<m18391125066@163.com>
250 Mail OK
RCPT TO:<1801875581@qq.com>
250 Mail OK
DEBUG SMTP: Verified Addresses
DEBUG SMTP: 1801875581@qq.com
DATA
354 End data with <CR><LF>.<CR><LF>
Date: Sat, 8 Jul 2023 19:58:44 +0800 (CST)
From: m18391125066@163.com
To: 1801875581@qq.com
Message-ID: <1028214719.0.1688817524899@LAPTOP-6GE885FP>
Subject: =?GBK?Q?=D5=E2=CA=C7=C0=B4=D7=D4Gyppppppppppppppppppppppp?=
=?GBK?Q?ppppppppppppppppppppppppppp=B5=C4=D3=CA=BC=FE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
hahhhhhhhhhhhhhh
.
250 Mail OK queued as zwqz-smtp-mta-g1-3,_____wA3hi51T6lkpTUyCA--.50930S3 1688817527
DEBUG SMTP: message successfully delivered to mail server
QUIT
221 Bye
3. 发送带有html标签的邮件
和发送文本邮件类似,只需要在message.setText(body,"utf-8")的基础上传入第三个参数"html",即message.setText(body,"utf-8","html"),这样正文中就可以识别html标签并展示相应的效果。
message.setText("<b>hahhhhh</b>hhhhhhhhh","utf-8","html"); // 设置邮件正文
4. 发送带有附件的邮件
要想携带附件,setText()方法就不再适用,而是要构造一个Multipart对象:
//邮件中既包含正文,又包含附件正文
//正文
BodyPart textPart = new MimeBodyPart();
StringBuilder contentText = new StringBuilder();
contentText.append("<h3>海边的曼彻斯特</h3>");
contentText.append("<p>I cant beat it</p>");
textPart.setContent(contentText.toString(),"text/html;charset=utf-8");
//附件
BodyPart imagePart = new MimeBodyPart();
imagePart.setFileName("附件名称");
imagePart.setDataHandler(new DataHandler(
new ByteArrayDataSource(Files.readAllBytes(Paths.get("d:\\file\\Manchester.webp")), "application/octet-stream")));
//将正文和附件部分组装成Multipart对象
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(textPart);
multipart.addBodyPart(imagePart);
//将multipart对象放入邮件
message.setContent(multipart);
运行结果: 带有附件
5. 发送内嵌图片的html邮件
如果需要在HTML邮件中内嵌图片,可以选择在html邮件中加入<img src=""> 的标签,这样的外部图片链接通常会被邮件客户端过滤,并提示用户显示图片并不安全。只有内嵌的图片才能正常在邮件中显示。所以,这种方式并不推荐。
推荐将内嵌图片作为一个附件嵌入邮件,即邮件本身也是 Multipart ,但需要在带有附件的邮件发送程序上做一点额外的处理:
contentText.append("<img scr=\"cid:Manchester\">"); // 在正文部分中加入html标签
imagePart.setHeader("Content-ID","Manchester");// 在附件部分设置图片内容的id
四. 小结
- 使用JavaMail API发送邮件本质上是一个MUA软件通过SMTP协议发送邮件至MTA服务器
- 打开调试模式可以看到详细的SMTP交互信息
- 某些邮件服务商需要开启SMTP,并需要独立的SMTP登录密码