Java实现邮件群发案例

wen java案例 1

本文目录导读:

Java实现邮件群发案例

  1. Maven依赖
  2. 邮件配置类
  3. 邮件实体类
  4. 邮件发送服务类
  5. 模板渲染服务
  6. 批量发送工具类
  7. 使用示例
  8. 配置文件示例 (application.properties)
  9. 注意事项

下面是一个完整的Java邮件群发案例,包含SMTP配置、HTML邮件、附件发送、多收件人处理以及异常处理。

Maven依赖

<dependencies>
    <!-- JavaMail -->
    <dependency>
        <groupId>com.sun.mail</groupId>
        <artifactId>javax.mail</artifactId>
        <version>1.6.2</version>
    </dependency>
    <!-- 或使用Jakarta Mail(适用于新版本) -->
    <!-- <dependency>
        <groupId>org.eclipse.angus</groupId>
        <artifactId>angus-mail</artifactId>
        <version>2.0.1</version>
    </dependency> -->
</dependencies>

邮件配置类

import java.util.Properties;
public class MailConfig {
    // SMTP服务器配置
    public static final String SMTP_HOST = "smtp.qq.com";
    public static final String SMTP_PORT = "465";
    public static final String SMTP_SSL = "true";
    public static final String AUTH_USERNAME = "your-email@qq.com";
    public static final String AUTH_PASSWORD = "your-authorization-code";
    public static Properties getMailProperties() {
        Properties props = new Properties();
        props.put("mail.smtp.host", SMTP_HOST);
        props.put("mail.smtp.port", SMTP_PORT);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.ssl.enable", SMTP_SSL);
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port", SMTP_PORT);
        props.put("mail.smtp.connectiontimeout", 5000);
        props.put("mail.smtp.timeout", 5000);
        props.put("mail.smtp.writetimeout", 5000);
        return props;
    }
}

邮件实体类

import java.util.List;
import java.util.Map;
public class EmailMessage {
    private List<String> toRecipients;     // 收件人列表
    private List<String> ccRecipients;     // 抄送人列表
    private List<String> bccRecipients;    // 密送人列表
    private String subject;                // 邮件主题
    private String htmlContent;           // HTML内容
    private String textContent;           // 纯文本内容
    private Map<String, byte[]> attachments; // 附件列表
    // 构造函数、getter和setter
    public EmailMessage() {}
    public EmailMessage(List<String> toRecipients, String subject, String content) {
        this.toRecipients = toRecipients;
        this.subject = subject;
        this.htmlContent = content;
    }
    // Getters and Setters
    public List<String> getToRecipients() { return toRecipients; }
    public void setToRecipients(List<String> toRecipients) { this.toRecipients = toRecipients; }
    public List<String> getCcRecipients() { return ccRecipients; }
    public void setCcRecipients(List<String> ccRecipients) { this.ccRecipients = ccRecipients; }
    public List<String> getBccRecipients() { return bccRecipients; }
    public void setBccRecipients(List<String> bccRecipients) { this.bccRecipients = bccRecipients; }
    public String getSubject() { return subject; }
    public void setSubject(String subject) { this.subject = subject; }
    public String getHtmlContent() { return htmlContent; }
    public void setHtmlContent(String htmlContent) { this.htmlContent = htmlContent; }
    public String getTextContent() { return textContent; }
    public void setTextContent(String textContent) { this.textContent = textContent; }
    public Map<String, byte[]> getAttachments() { return attachments; }
    public void setAttachments(Map<String, byte[]> attachments) { this.attachments = attachments; }
}

邮件发送服务类

import javax.mail.*;
import javax.mail.internet.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EmailSenderService {
    private static EmailSenderService instance;
    private final Session session;
    private final ExecutorService executorService;
    private EmailSenderService() {
        Properties props = MailConfig.getMailProperties();
        session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                    MailConfig.AUTH_USERNAME, 
                    MailConfig.AUTH_PASSWORD
                );
            }
        });
        // 开启调试模式(生产环境建议关闭)
        // session.setDebug(true);
        // 创建线程池用于异步发送
        executorService = Executors.newFixedThreadPool(10);
    }
    public static synchronized EmailSenderService getInstance() {
        if (instance == null) {
            instance = new EmailSenderService();
        }
        return instance;
    }
    /**
     * 异步发送邮件
     */
    public void sendEmailAsync(EmailMessage emailMessage) {
        executorService.submit(() -> {
            try {
                sendEmail(emailMessage);
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        });
    }
    /**
     * 同步发送邮件
     */
    public void sendEmail(EmailMessage emailMessage) throws MessagingException {
        Message message = createMessage(emailMessage);
        Transport.send(message);
        System.out.println("邮件发送成功!");
    }
    /**
     * 创建邮件消息
     */
    private Message createMessage(EmailMessage emailMessage) throws MessagingException {
        MimeMessage message = new MimeMessage(session);
        // 发件人
        message.setFrom(new InternetAddress(MailConfig.AUTH_USERNAME));
        // 收件人
        List<String> toList = emailMessage.getToRecipients();
        if (toList != null && !toList.isEmpty()) {
            InternetAddress[] toAddresses = new InternetAddress[toList.size()];
            for (int i = 0; i < toList.size(); i++) {
                toAddresses[i] = new InternetAddress(toList.get(i));
            }
            message.setRecipients(Message.RecipientType.TO, toAddresses);
        }
        // 抄送
        List<String> ccList = emailMessage.getCcRecipients();
        if (ccList != null && !ccList.isEmpty()) {
            InternetAddress[] ccAddresses = new InternetAddress[ccList.size()];
            for (int i = 0; i < ccList.size(); i++) {
                ccAddresses[i] = new InternetAddress(ccList.get(i));
            }
            message.setRecipients(Message.RecipientType.CC, ccAddresses);
        }
        // 密送
        List<String> bccList = emailMessage.getBccRecipients();
        if (bccList != null && !bccList.isEmpty()) {
            InternetAddress[] bccAddresses = new InternetAddress[bccList.size()];
            for (int i = 0; i < bccList.size(); i++) {
                bccAddresses[i] = new InternetAddress(bccList.get(i));
            }
            message.setRecipients(Message.RecipientType.BCC, bccAddresses);
        }
        // 邮件主题
        message.setSubject(emailMessage.getSubject(), "UTF-8");
        // 邮件内容
        MimeMultipart multipart = new MimeMultipart();
        // HTML内容
        if (emailMessage.getHtmlContent() != null && !emailMessage.getHtmlContent().isEmpty()) {
            BodyPart htmlPart = new MimeBodyPart();
            htmlPart.setContent(emailMessage.getHtmlContent(), "text/html;charset=UTF-8");
            multipart.addBodyPart(htmlPart);
        }
        // 纯文本内容
        if (emailMessage.getTextContent() != null && !emailMessage.getTextContent().isEmpty()) {
            BodyPart textPart = new MimeBodyPart();
            textPart.setText(emailMessage.getTextContent());
            multipart.addBodyPart(textPart);
        }
        // 附件
        Map<String, byte[]> attachments = emailMessage.getAttachments();
        if (attachments != null && !attachments.isEmpty()) {
            for (Map.Entry<String, byte[]> entry : attachments.entrySet()) {
                BodyPart attachmentPart = new MimeBodyPart();
                attachmentPart.setFileName(entry.getKey());
                attachmentPart.setContent(entry.getValue(), "application/octet-stream");
                multipart.addBodyPart(attachmentPart);
            }
        }
        message.setContent(multipart);
        return message;
    }
    /**
     * 关闭线程池
     */
    public void shutdown() {
        executorService.shutdown();
    }
}

模板渲染服务

import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class TemplateService {
    /**
     * 简单的模板渲染(支持占位符替换)
     * Hello ${name}, welcome!
     */
    public static String renderTemplate(String template, Map<String, String> variables) {
        for (Map.Entry<String, String> entry : variables.entrySet()) {
            template = template.replace("${" + entry.getKey() + "}", entry.getValue());
        }
        return template;
    }
    /**
     * 创建一个默认的HTML模板
     */
    public static String getDefaultTemplate(String title, String content, String footer) {
        return String.format("""
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <title>%s</title>
                <style>
                    body {
                        font-family: Arial, sans-serif;
                        background-color: #f4f4f4;
                        margin: 0;
                        padding: 20px;
                    }
                    .container {
                        background-color: #ffffff;
                        border-radius: 8px;
                        padding: 30px;
                        margin: auto;
                        max-width: 600px;
                        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                    }
                    h1 {
                        color: #333;
                        text-align: center;
                    }
                    p {
                        color: #666;
                        line-height: 1.6;
                    }
                    .footer {
                        color: #999;
                        font-size: 12px;
                        text-align: center;
                        margin-top: 20px;
                        border-top: 1px solid #eee;
                        padding-top: 15px;
                    }
                </style>
            </head>
            <body>
                <div class="container">
                    <h1>%s</h1>
                    %s
                    <div class="footer">%s</div>
                </div>
            </body>
            </html>
            """, title, title, content, footer);
    }
}

批量发送工具类

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class BulkEmailSender {
    /**
     * 批量发送个性化邮件
     * @param recipientList 收件人列表
     * @param subject 邮件主题模板
     * @param contentTemplate 内容模板(使用${name}等占位符)
     * @param variablesList 每个收件人对应的变量列表
     */
    public static void sendBulkEmails(List<String> recipientList, 
                                     String subject,
                                     String contentTemplate,
                                     List<Map<String, String>> variablesList) {
        EmailSenderService sender = EmailSenderService.getInstance();
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        for (int i = 0; i < recipientList.size(); i++) {
            String recipient = recipientList.get(i);
            Map<String, String> variables = variablesList.get(i);
            // 渲染个性化内容
            String personalizedContent = TemplateService.renderTemplate(contentTemplate, variables);
            String personalizedSubject = TemplateService.renderTemplate(subject, variables);
            // 发送邮件(异步)
            EmailMessage email = new EmailMessage();
            List<String> recipients = new ArrayList<>();
            recipients.add(recipient);
            email.setToRecipients(recipients);
            email.setSubject(personalizedSubject);
            email.setHtmlContent(personalizedContent);
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try {
                    sender.sendEmail(email);
                } catch (Exception e) {
                    System.err.println("发送到 " + recipient + " 失败: " + e.getMessage());
                }
            });
            futures.add(future);
        }
        // 等待所有邮件发送完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .join();
    }
    /**
     * 分批发送(避免一次发送过多)
     */
    public static void sendBulkEmailsInBatches(List<String> recipients,
                                               String subject,
                                               String content,
                                               int batchSize) {
        int total = recipients.size();
        int batchCount = (total + batchSize - 1) / batchSize;
        for (int i = 0; i < batchCount; i++) {
            int fromIndex = i * batchSize;
            int toIndex = Math.min((i + 1) * batchSize, total);
            List<String> batchRecipients = recipients.subList(fromIndex, toIndex);
            List<Map<String, String>> variablesList = new ArrayList<>();
            for (String recipient : batchRecipients) {
                Map<String, String> vars = new HashMap<>();
                vars.put("recipient", recipient);
                variablesList.add(vars);
            }
            String batchSubject = TemplateService.renderTemplate(subject, 
                Map.of("batch", String.valueOf(i + 1), "total", String.valueOf(batchCount)));
            sendBulkEmails(batchRecipients, batchSubject, content, variablesList);
            // 批次之间暂停
            try {
                Thread.sleep(5000); // 5秒后发送下一批
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

使用示例

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EmailDemo {
    public static void main(String[] args) {
        // 示例1:发送简单邮件
        simpleEmailDemo();
        // 示例2:批量个性化邮件
        bulkEmailDemo();
        // 示例3:带附件的邮件
        attachmentEmailDemo();
    }
    /**
     * 简单邮件发送
     */
    public static void simpleEmailDemo() {
        EmailMessage email = new EmailMessage();
        List<String> recipients = new ArrayList<>();
        recipients.add("recipient1@example.com");
        recipients.add("recipient2@example.com");
        email.setToRecipients(recipients);
        email.setSubject("【测试邮件】欢迎使用Java邮件服务");
        email.setHtmlContent("""
            <html>
                <body>
                    <h1>欢迎使用Java邮件服务</h1>
                    <p>这是一封测试邮件,如果您收到此邮件,说明配置成功。</p>
                    <p>发送时间:<span style="color: blue;">%s</span></p>
                </body>
            </html>
            """.formatted(new java.util.Date().toString()));
        EmailSenderService sender = EmailSenderService.getInstance();
        try {
            sender.sendEmail(email);
            System.out.println("简单邮件发送成功!");
        } catch (Exception e) {
            System.err.println("发送失败: " + e.getMessage());
        }
    }
    /**
     * 批量个性化邮件
     */
    public static void bulkEmailDemo() {
        // 收件人列表
        List<String> recipients = new ArrayList<>();
        recipients.add("user1@example.com");
        recipients.add("user2@example.com");
        recipients.add("user3@example.com");
        recipients.add("user4@example.com");
        recipients.add("user5@example.com");
        // 邮件模板
        String subjectTemplate = "【${company}】${name},您的专属优惠来了!";
        String contentTemplate = """
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <title>优惠通知</title>
            </head>
            <body>
                <h2>亲爱的 ${name}:</h2>
                <p>您好!${company} 为您准备了专属优惠。</p>
                    <p>您的专属优惠码:<strong style="color: red;">${coupon}</strong></p>
                    <p>有效期至:${expireDate}</p>
                    <p>立即使用:<a href="${website}">点击访问</a></p>
                <br>
                <p>感谢您的支持!</p>
            </body>
            </html>
            """;
        // 每个收件人的个性化变量
        List<Map<String, String>> variablesList = new ArrayList<>();
        for (int i = 1; i <= recipients.size(); i++) {
            Map<String, String> vars = new HashMap<>();
            vars.put("name", "用户" + i);
            vars.put("company", "Java邮件服务");
            vars.put("coupon", "SAVE" + (100 + i * 10));
            vars.put("expireDate", "2024年12月31日");
            vars.put("website", "https://www.example.com");
            vars.put("batch", "1");
            vars.put("total", "1");
            variablesList.add(vars);
        }
        // 发送批量邮件
        BulkEmailSender.sendBulkEmails(recipients, subjectTemplate, contentTemplate, variablesList);
        System.out.println("批量邮件发送完成!");
    }
    /**
     * 带附件的邮件
     */
    public static void attachmentEmailDemo() {
        EmailMessage email = new EmailMessage();
        List<String> recipients = new ArrayList<>();
        recipients.add("recipient@example.com");
        email.setToRecipients(recipients);
        email.setSubject("【资料文件】2014年项目报告");
        email.setHtmlContent("""
            <html>
                <body>
                    <h2>项目报告</h2>
                    <p>请查收附件中的项目报告。</p>
                    <p>如有问题,请随时联系我们。</p>
                </body>
            </html>
            """);
        // 添加附件
        Map<String, byte[]> attachments = new HashMap<>();
        attachments.put("报告文档.txt", "这是文档内容".getBytes());
        attachments.put("财务数据.csv", "日期,收入,支出\n2024-01,10000,5000".getBytes());
        email.setAttachments(attachments);
        EmailSenderService sender = EmailSenderService.getInstance();
        try {
            sender.sendEmail(email);
            System.out.println("带附件邮件发送成功!");
        } catch (Exception e) {
            System.err.println("发送失败: " + e.getMessage());
        }
    }
}

配置文件示例 (application.properties)

# SMTP配置
mail.smtp.host=smtp.qq.com
mail.smtp.port=465
mail.smtp.auth=true
mail.smtp.ssl.enable=true
mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
# 账号信息
mail.username=your-email@qq.com
mail.password=your-authorization-code
# 邮件发送配置
mail.batch.size=50
mail.batch.delay=5000
mail.default.encoding=UTF-8

注意事项

  • SMTP服务器配置:不同的邮箱服务商(QQ邮箱、163邮箱、Gmail等)有不同的SMTP服务器配置,需要根据实际情况调整。

  • 授权码:不要使用邮箱密码,使用邮箱服务商提供的授权码(如QQ邮箱的授权码)。

  • 发送限制:各大邮件服务商对每日发送数量有限制,请合理控制发送频率和数量。

  • 线程安全EmailSenderService使用单例模式,并提供了异步发送方法。

  • 错误处理:在实际项目中,建议添加完善的日志记录和重试机制。

  • 敏感信息:授权码等敏感信息不要硬编码,应该从配置文件或环境变量中读取。

抱歉,评论功能暂时关闭!