| 知乎专栏 |
原生 jakarta.mail 例子
<!-- Source: https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
package cn.netkiller.component;
import jakarta.activation.DataHandler;
import jakarta.activation.URLDataSource;
import jakarta.mail.*;
import jakarta.mail.internet.*;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.util.*;
@Component
public class EmailComponent {
protected final Map<String, SequencedMap<String, String>> emailAccount = new HashMap<String, SequencedMap<String, String>>() {{
put("outlook", new LinkedHashMap<>() {{
put("host", "smtp-mail.outlook.com");
put("port", "587");
put("auth", "true");
put("username", "netkiller@outlook.com");
put("password", "5BtS7vR4");
}});
put("exmail", new LinkedHashMap<>() {{
put("host", "smtp.exmail.qq.com");
put("port", "465");
put("auth", "true");
put("username", "neo@netkiller.cn");
put("password", "h2yVh5XJ2vyg972i");
}});
}};
@Retryable(
value = {MessagingException.class}
)
public void sendEmailWithAttachment(String to, String subject, String body, String filePath) throws Exception {
SequencedMap<String, String> account = emailAccount.get("outlook");
// 配置SMTP服务器
Properties properties = new Properties();
properties.put("mail.smtp.host", account.get("host")); // 替换为SMTP服务器地址
properties.put("mail.smtp.port", account.get("port"));
properties.put("mail.smtp.auth", account.get("auth"));
properties.put("mail.user", account.get("username"));
properties.put("mail.password", account.get("password"));
// TLS
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.starttls.required", "true");
// SSL
// properties.put("mail.transport.protocol", "smtps");
// properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.protocols", "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;");
properties.put("mail.smtp.ssl.ciphersuites", "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:RC4-MD5:RC4-SHA;");
properties.put("mail.smtp.ssl.trust", "*"); // 信任所有证书
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.socketFactory.fallback", "false");
// 创建会话
Session session = Session.getInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(account.get("username"), account.get("password")); // 替换为邮箱和授权码
}
});
session.setDebug(true);
// 创建邮件
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(account.get("username")));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject);
// 设置邮件内容和附件
Multipart multipart = new MimeMultipart();
// 添加文本内容
MimeBodyPart textPart = new MimeBodyPart();
textPart.setText(body);
multipart.addBodyPart(textPart);
// 添加附件
// MimeBodyPart attachmentPart = new MimeBodyPart();
// attachmentPart.attachFile(filePath);
// multipart.addBodyPart(attachmentPart);
// URL 网络附件
String url = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
MimeBodyPart attachmentPart = new MimeBodyPart();
attachmentPart.setDataHandler(new DataHandler(new URLDataSource(new URL(url))));
attachmentPart.setFileName(MimeUtility.encodeText("logo.png"));
multipart.addBodyPart(attachmentPart);
message.setContent(multipart);
// 发送邮件
Transport.send(message);
}
}
Springboot 封装的 jakarta.mail
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
例 26.6. Spring boot with Email (pom.xml)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>netkiller.cn</groupId>
<artifactId>api.netkiller.cn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>api.netkiller.cn</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-oracle</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<!-- <version>12.1.0.1</version> -->
<version>11.2.0.3</version>
<scope>system</scope>
<systemPath>${basedir}/lib/ojdbc6.jar</systemPath>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source />
<target />
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.properties
Postfix / Exam4 / Sendmail 邮件服务器配置
spring.mail.host=smtp.163.com
SMTP 配置
spring.mail.host=smtp.163.com
spring.mail.username=openunix@163.com
spring.mail.password=your_password
spring.mail.properties.mail.smtp.auth=true
#spring.mail.properties.mail.smtp.starttls.enable=true
#spring.mail.properties.mail.smtp.starttls.required=true
package api.pojo;
public class Email {
public String from;
public String to;
public String subject;
public String text;
public boolean status;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
@Override
public String toString() {
return "Email [from=" + from + ", to=" + to + ", subject=" + subject + ", text=" + text + "]";
}
public Email() {
}
public Email(String from, String to, String subject, String text) {
super();
this.from = from;
this.to = to;
this.subject = subject;
this.text = text;
}
}
package api.rest;
import java.io.File;
import javax.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import api.pojo.Email;
@RestController
@RequestMapping("/v1/email")
public class EmailRestController extends CommonRestController {
@Autowired
private JavaMailSender javaMailSender;
@RequestMapping("version")
@ResponseStatus(HttpStatus.OK)
public String version() {
return "[OK] Welcome to withdraw Restful version 1.0";
}
@RequestMapping(value = "send", method = RequestMethod.POST, produces = { "application/xml", "application/json" })
public ResponseEntity<Email> sendSimpleMail(@RequestBody Email email) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(email.getFrom());
message.setTo(email.getTo());
message.setSubject(email.getSubject());
message.setText(email.getText());
javaMailSender.send(message);
email.setStatus(true);
return new ResponseEntity<Email>(email, HttpStatus.OK);
}
@RequestMapping(value = "attachments", method = RequestMethod.POST, produces = { "application/xml", "application/json" })
public ResponseEntity<Email> attachments(@RequestBody Email email) throws Exception {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
mimeMessageHelper.setFrom(email.getFrom());
mimeMessageHelper.setTo(email.getTo());
mimeMessageHelper.setSubject(email.getSubject());
mimeMessageHelper.setText("<html><body><img src=\"cid:banner\" >" + email.getText() + "</body></html>", true);
FileSystemResource file = new FileSystemResource(new File("banner.jpg"));
mimeMessageHelper.addInline("banner", file);
FileSystemResource fileSystemResource = new FileSystemResource(new File("Attachment.jpg"));
mimeMessageHelper.addAttachment("Attachment.jpg", fileSystemResource);
javaMailSender.send(mimeMessage);
email.setStatus(true);
return new ResponseEntity<Email>(email, HttpStatus.OK);
}
// 如果你不想使用 application.properties 中的 spring.mail.host 配置,想自行配置SMTP主机可以参考下面例子
@RequestMapping(value = "sendmail", method = RequestMethod.POST, produces = { "application/xml", "application/json" })
public ResponseEntity<Email> sendmail(@RequestBody Email email) {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(email.getHost());
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(email.getFrom());
message.setTo(email.getTo());
message.setSubject(email.getSubject());
message.setText(email.getText());
try{
javaMailSender.send(message);
email.setStatus(true);
}catch(Exception e){
email.setText(e.getMessage());
email.setStatus(false);
}
return new ResponseEntity<Email>(email, HttpStatus.OK);
}
}
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"from":"root@netkiller.cn", "to":"21214094@qq.com","subject":"Hello","text":"Hello world!!!"}' http://172.16.0.20:8080/v1/email/send.json
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 10 Aug 2016 06:38:00 GMT
{"from":"root@netkiller.cn","to":"21214094@qq.com","subject":"Hello","text":"Hello world!!!","status":true}
ssl smtp 配置 spring.mail.properties.mail.smtp.ssl.enable=true
# Email spring.mail.host=smtp.exmail.qq.com spring.mail.username=chenjingfeng@netkiller.cn spring.mail.password=h2yVg972h5XJ2vyi spring.mail.port=465 spring.mail.default-encoding=UTF-8 spring.mail.properties.mail.transport.protocol=smtp spring.mail.properties.mail.smtp.connectiontimeout=5000 spring.mail.properties.mail.smtp.timeout=3000 spring.mail.properties.mail.smtp.writetimeout=5000 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.ssl.enable=true spring.mail.properties.mail.debug=true
tls smtp 配置 spring.mail.properties.mail.smtp.starttls.enable=true
# Email spring.mail.host=smtp.exmail.qq.com spring.mail.username=chenjingfeng@netkiller.cn spring.mail.password=h2yVg972h5XJ2vyi spring.mail.port=465 spring.mail.default-encoding=UTF-8 spring.mail.properties.mail.transport.protocol=smtp spring.mail.properties.mail.smtp.connectiontimeout=5000 spring.mail.properties.mail.smtp.timeout=3000 spring.mail.properties.mail.smtp.writetimeout=5000 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true spring.mail.properties.mail.debug=true
发送文本邮件
package cn.netkiller.component;
import jakarta.mail.MessagingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.stereotype.Component;
@Component
public class EmailComponent {
@Autowired
private JavaMailSender javaMailSender;
@Retryable(value = {MessagingException.class})
public void sendTextEmail(String to, String subject, String body) {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom("chenjingfeng@netkiller.cn");
simpleMailMessage.setTo("netkiller@msn.com");
simpleMailMessage.setSubject("Hello");
simpleMailMessage.setText("Hello world");
try {
javaMailSender.send(simpleMailMessage);
} catch (MailException ex) {
System.err.println(ex.getMessage());
}
}
}
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
mimeMessageHelper.setFrom(from);
mimeMessageHelper.setTo(to);
mimeMessageHelper.setSubject(subject);
mimeMessageHelper.setText(body, true); // true = 支持HTML
package cn.netkiller.component;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.net.URL;
@Component
public class EmailComponent {
// private final String from = "NoReply <noreply@elastolink.com>";
private final String from = "Elastolink<chenjingfeng@weilaizhihui.com.cn>";
@Autowired
private JavaMailSender javaMailSender;
@Retryable(value = {MessagingException.class})
public void sendTextEmail(String to, String subject, String body) {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom(from);
simpleMailMessage.setTo(to);
simpleMailMessage.setSubject("Hello");
simpleMailMessage.setText("thank you for placing order. Your order number is ");
try {
javaMailSender.send(simpleMailMessage);
} catch (MailException ex) {
System.err.println(ex.getMessage());
}
}
public void sendEmailWithAttachment(String to, String subject, String body, String filePath) throws Exception {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
// 第二个参数 true = 开启附件模式
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
mimeMessageHelper.setFrom(from);
mimeMessageHelper.setTo(to);
mimeMessageHelper.setSubject(subject);
mimeMessageHelper.setText(body, true); // true = 支持HTML
// =============================================
// 核心:从 URL 读取流,直接作为附件发送(不存本地)
// =============================================
try (InputStream inputStream = new URL(filePath).openStream()) {
InputStreamSource source = new ByteArrayResource(inputStream.readAllBytes());
mimeMessageHelper.addAttachment("附件测试.png", source);
}
javaMailSender.send(mimeMessage);
}
}