当前位置:首页 > 后端开发 > 正文

java 怎么实现邮件发送

Java可通过JavaMail API实现邮件发送,需配置SMTP服务器参数,创建会话及邮件对象后

技术原理与前置条件

1 核心机制

邮件发送基于 SMTP(Simple Mail Transfer Protocol) 协议,其工作流程为:

  1. 客户端(Java程序)→ 建立TCP连接至SMTP服务器(默认端口25/465/587);
  2. 身份验证(用户名+密码/OAuth2);
  3. 构造邮件内容(含头部字段+正文/附件);
  4. 服务器接收并转发至目标邮箱。
要素 说明
发件人 需真实存在的有效邮箱账号
收件人 支持单人/多人/抄送/密送
邮件服务器 根据服务商选择(如Exchange、Postfix、云服务厂商)
安全层 SSL/TLS加密(推荐端口465或587),明文传输已逐渐被淘汰
第三方库 JavaMail API(现称 Jakarta Mail),底层依赖 javax.mail JAR包

2 环境准备

  • JDK版本:≥8(兼容新版JavaMail)
  • 依赖引入:Maven项目中添加以下依赖:
    <dependency>
        <groupId>com.sun.mail</groupId>
        <artifactId>javax.mail</artifactId>
        <version>1.6.2</version>
    </dependency>
  • 服务器配置:获取目标邮箱的SMTP服务器地址及端口(例:QQ邮箱 smtp.qq.com:465,阿里云邮箱 smtp.aliyun.com:465)。

分步实现详解

1 基础配置项解析

通过 Properties 对象定义邮件会话参数,关键属性如下表所示:

java 怎么实现邮件发送  第1张

属性名 示例值 作用
mail.smtp.host smtp.example.com 指定SMTP服务器域名
mail.smtp.port 465 SMTP服务端口(465=SSL, 587=STARTTLS, 25=明文)
mail.smtp.auth true 启用身份验证
mail.smtp.ssl.enable true 启用SSL加密(若端口为465必选)
mail.smtp.timeout 5000 连接超时时间(毫秒)
mail.smtp.socketFactory.class javax.net.ssl.SSLSocketFactory 强制使用SSL套接字工厂

2 核心代码实现(含附件)

以下为完整可运行的示例代码,包含纯文本、HTML内容及文件附件:

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.;
import javax.mail.internet.;
import java.util.Date;
import java.util.Properties;
public class EmailSender {
    public static void main(String[] args) throws Exception {
        // ========== 1. 配置会话属性 ==========
        Properties props = new Properties();
        props.put("mail.smtp.host", "smtp.example.com"); // 替换为你的SMTP服务器
        props.put("mail.smtp.port", "465");              // SSL端口
        props.put("mail.smtp.auth", "true");             // 启用认证
        props.put("mail.smtp.ssl.enable", "true");       // 启用SSL
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // 关键!
        // ========== 2. 创建会话对象 ==========
        Session session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("your_email@example.com", "your_password"); // 替换为你的邮箱和密码
            }
        });
        session.setDebug(true); // 开启调试日志(生产环境建议关闭)
        // ========== 3. 构建邮件消息 ==========
        Message message = new MimeMessage(session);
        message.setFrom(new InternetAddress("your_email@example.com")); // 发件人
        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("recipient@example.com")); // 收件人
        message.setSubject("Java邮件测试 " + new Date()); // 主题+时间戳
        // 创建多部分容器(支持混合内容)
        Multipart multipart = new MimeMultipart();
        // 添加文本部分(可选HTML)
        BodyPart textPart = new MimeBodyPart();
        textPart.setContent("<h1>这是一封测试邮件</h1><p>当前时间:" + new Date() + "</p>", "text/html;charset=UTF-8");
        multipart.addBodyPart(textPart);
        // 添加附件(示例:上传本地文件)
        BodyPart attachmentPart = new MimeBodyPart();
        FileDataSource fds = new FileDataSource("C:\test.pdf"); // 替换为你的文件路径
        attachmentPart.setDataHandler(new DataHandler(fds));
        attachmentPart.setFileName(MimeUtility.encodeText("测试附件.pdf")); // 处理中文文件名乱码
        multipart.addBodyPart(attachmentPart);
        // 将多部分内容设置到邮件中
        message.setContent(multipart);
        message.setSentDate(new Date()); // 设置发送时间
        // ========== 4. 发送邮件 ==========
        Transport.send(message);
        System.out.println("邮件发送成功!");
    }
}

3 关键细节说明

  • 中文乱码解决:对主题、文件名等非ASCII字符需使用 MimeUtility.encodeText() 进行Base64编码。
  • 大文件附件优化:若附件超过10MB,建议分块读取或使用流式处理避免内存溢出。
  • 异步发送:可通过 Transport.send(message, new SendHandler()) 结合线程池实现异步发送,提升性能。
  • 特殊字符转义:在HTML内容中,<>& 等符号需转义为 &lt;&gt;&amp;

常见问题与解决方案

1 典型错误排查表

现象 可能原因 解决方案
Authentication failed 账号/密码错误或未开启SMTP服务 检查邮箱设置,部分服务商需生成授权码
Connection refused 防火墙拦截或端口错误 确认端口开放(如465/587),关闭代理软件
Timeout occurred 网络延迟或服务器响应慢 增加 mail.smtp.timeout 值至10秒以上
附件显示为临时文件名 未正确设置 setFileName() 使用 MimeUtility.encodeText() 包装文件名
收到空邮件 未正确设置邮件内容类型 检查 setContentType() 和编码格式

2 主流邮箱服务商特殊要求

服务商 SMTP服务器 推荐端口 注意事项
Gmail smtp.gmail.com 465/587 需开启“允许不够安全的应用”,或使用OAuth2
Outlook smtp.office365.com 587 需开启双重验证并创建应用密码
QQ邮箱 smtp.qq.com 465 需在邮箱设置中开启SMTP服务
阿里云邮箱 smtp.aliyun.com 465 需在控制台开通SMTP服务并获取授权码

扩展功能建议

  • 模板引擎集成:结合Thymeleaf/FreeMarker实现动态邮件模板。
  • 日志记录:记录发送状态(成功/失败)、耗时、错误信息至数据库。
  • 重试机制:对临时性失败(如网络波动)进行指数退避重试。
  • 批量发送优化:使用 Transport.send(message, addressList) 批量发送,减少连接次数。
  • DKIM签名:通过 message.saveChanges() + 自定义DKIM头增强防垃圾邮件能力。

FAQs

Q1: 为什么我的程序能连接SMTP服务器但无法发送邮件?

A: 常见原因包括:① 发件人邮箱未在服务商处开通SMTP服务;② 账号密码错误(注意部分服务商要求使用应用专用密码而非登录密码);③ 邮件内容被判定为垃圾邮件(尝试简化内容或添加SPF/DKIM记录),建议开启调试日志(session.setDebug(true))查看详细错误信息。

Q2: 如何发送带有内嵌图片的HTML邮件?

A: 需将图片作为CIMG类型附件嵌入,步骤:① 将图片文件转为Base64编码;② 在HTML中使用 <img src="cid:imageId">;③ 创建 MimeBodyPart 并设置 ContentIDimageId,示例代码片段:

// 图片部分
BodyPart imagePart = new MimeBodyPart();
imagePart.setDataHandler(new DataHandler(new FileDataSource("logo.png")));
imagePart.setHeader("Content-ID", "<logo>"); // 与HTML中的cid对应
multipart.addBody
0