Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

1.33. Spring boot with Email

jakarta.mail

原生 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);
    }
}

			
		

1.33.1. spring-boot-starter-mail

Springboot 封装的 jakarta.mail

Maven

        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>	
        
			

例 1.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>

            
				

Resource

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  
        
			

POJO

        
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;
}

}

        
			

RestController

        
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);
}	
}
        
			

Test

        
$ 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}
        
			

1.33.2. 用法详解

开启 DEBUG

		
spring.mail.properties.mail.debug=true
		
			

SMTP SSL 配置

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
			
			

SMTP TLS 配置

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());
        }
    }
}
			
			

发送HTML邮件

			
        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);
        
    }
}