Servlet 发送电子邮件

Servlet 发送电子邮件讲解

Servlet 可以实现发送电子邮件的功能,这在 Web 应用中很常见,例如用户注册确认、密码重置或通知服务。Servlet 通过 JavaMail API 来发送邮件,需要引入相关依赖。以下用中文详细讲解 Servlet 发送电子邮件的过程,包括基本概念、代码示例、处理中文内容和注意事项。


1. 什么是 JavaMail API?

JavaMail 是 Java 平台用于处理电子邮件的标准 API,它支持 SMTP、POP3 和 IMAP 等协议。在 Servlet 中,我们主要使用 SMTP 协议发送邮件。

  • 用途
  • 发送文本邮件、HTML 邮件或带附件的邮件。
  • 支持群发、抄送等功能。
  • 依赖
  • 需要添加 javax.mail 库(在 Maven 中添加依赖:<dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version></dependency>)。
  • 如果使用 Jakarta EE,依赖为 jakarta.mail:jakarta.mail-api 和实现库如 com.sun.mail:jakarta.mail

注意:JavaMail 不直接发送邮件,而是通过邮件服务器(如 Gmail、QQ 邮箱)中转。需要配置服务器的 SMTP 主机、端口、用户名和密码。


2. Servlet 发送邮件的基本步骤

  1. 导入必要类import javax.mail.*; 等。
  2. 创建 Session:配置邮件服务器属性。
  3. 创建 Message:设置发件人、收件人、主题和内容。
  4. 发送邮件:使用 Transport 发送。

(1) 配置邮件服务器

常用邮件服务器配置示例:

  • Gmail:主机 smtp.gmail.com,端口 465(SSL)或 587(TLS),需要启用“允许不安全应用”或使用应用专用密码。
  • QQ 邮箱:主机 smtp.qq.com,端口 465(SSL),需要授权码。

(2) 代码示例:发送简单文本邮件

以下是 Servlet 中发送纯文本邮件的示例。假设从表单提交接收收件人邮箱和内容。

Servlet 代码(SendMailServlet)

import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.IOException;
import java.util.Properties;

public class SendMailServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws IOException {
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");

        // 获取表单数据
        String to = request.getParameter("to"); // 收件人邮箱
        String subject = request.getParameter("subject"); // 主题
        String content = request.getParameter("content"); // 内容

        // 邮件服务器配置(以 QQ 邮箱为例)
        final String from = "your_email@qq.com"; // 发件人邮箱
        final String password = "your_auth_code"; // 授权码(非密码)
        String host = "smtp.qq.com"; // SMTP 主机
        int port = 465; // 端口

        // 配置 Properties
        Properties props = new Properties();
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.port", String.valueOf(port));
        props.put("mail.smtp.auth", "true"); // 需要认证
        props.put("mail.smtp.ssl.enable", "true"); // 启用 SSL(或 TLS)

        // 创建 Session
        Session session = Session.getInstance(props, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(from, password);
            }
        });

        try {
            // 创建 Message
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from)); // 发件人
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); // 收件人
            message.setSubject(subject); // 主题
            message.setText(content); // 内容(纯文本)

            // 发送邮件
            Transport.send(message);

            response.getWriter().write("邮件发送成功!");
        } catch (MessagingException e) {
            response.getWriter().write("邮件发送失败:" + e.getMessage());
            e.printStackTrace();
        }
    }
}

HTML 表单(发送页面)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>发送邮件</title>
</head>
<body>
    <form action="/sendMail" method="post">
        收件人:<input type="text" name="to"><br>
        主题:<input type="text" name="subject"><br>
        内容:<textarea name="content"></textarea><br>
        <input type="submit" value="发送">
    </form>
</body>
</html>

说明

  • 使用 Properties 配置服务器。
  • Authenticator 提供认证信息。
  • MimeMessage 支持 MIME 类型,setText() 设置纯文本内容。
  • Transport.send() 发送邮件。

3. 发送 HTML 邮件或带附件邮件

(1) 发送 HTML 邮件

使用 MimeMultipart 创建多部分消息,将内容设置为 HTML。

代码片段(替换 setText)

// 创建多部分消息
MimeMultipart multipart = new MimeMultipart();

// HTML 部分
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<h1>欢迎!</h1><p>这是 HTML 邮件内容。</p>", "text/html;charset=UTF-8");
multipart.addBodyPart(htmlPart);

// 设置到 Message
message.setContent(multipart);

(2) 发送带附件邮件

添加附件部分。

代码片段(添加到 multipart)

// 附件部分
MimeBodyPart attachmentPart = new MimeBodyPart();
attachmentPart.attachFile("/path/to/file.txt"); // 文件路径
multipart.addBodyPart(attachmentPart);

完整示例:结合 HTML 和附件。

  • try 块中替换 message.setText(content); 为上述 multipart 代码。

4. 处理中文邮件

中文邮件容易出现乱码问题,需要确保编码一致。

  • 主题和内容编码
  • 使用 MimeUtility.encodeText() 对主题编码。
  • 内容使用 "text/html;charset=UTF-8""text/plain;charset=UTF-8"

代码示例:处理中文主题和内容

// 设置主题(支持中文)
message.setSubject(MimeUtility.encodeText(subject, "UTF-8", "B"));

// 设置内容(纯文本,支持中文)
message.setText(content, "UTF-8");

// 或 HTML 内容
htmlPart.setContent(content, "text/html;charset=UTF-8");

附件文件名中文

// 附件文件名编码
attachmentPart.setFileName(MimeUtility.encodeText("中文附件.txt", "UTF-8", "B"));

说明

  • "B" 表示 Base64 编码,适合中文。
  • 确保 Servlet 的 request.setCharacterEncoding("UTF-8"); 和响应编码一致。

5. 常用属性和扩展

  • 收件人类型
  • Message.RecipientType.TO:收件人。
  • Message.RecipientType.CC:抄送。
  • Message.RecipientType.BCC:密送。
  • 群发InternetAddress.parse("email1@example.com,email2@example.com")
  • 调试模式session.setDebug(true); 输出日志。
  • TLS 支持(非 SSL):
  props.put("mail.smtp.starttls.enable", "true");
  props.put("mail.smtp.ssl.enable", "false");

6. 注意事项

  1. 安全性和认证
  • 不要在代码中硬编码密码,使用配置文件或环境变量。
  • 对于 Gmail/QQ 等,需启用 SMTP 并使用授权码(非登录密码)。
  • 生产环境使用 SSL/TLS 加密传输。
  1. 中文编码问题
  • 始终指定 charset=UTF-8
  • 测试不同邮件客户端(如 Outlook、Webmail)显示效果。
  1. 异常处理
  • 捕获 MessagingException,常见错误:认证失败、主机不可达、端口错误。
  • 检查防火墙或网络是否允许 SMTP 端口。
  1. 性能和限制
  • 发送邮件是阻塞操作,建议异步处理(如使用线程或消息队列)。
  • 邮件服务器有发送限额(如 Gmail 每日 500 封),避免滥用。
  1. 依赖和兼容性
  • 在 Tomcat 等容器中,确保 JavaMail JAR 在 classpath。
  • Java 9+ 可能需 --add-opens 参数处理反射问题。
  1. 测试
  • 先用本地邮件服务器测试(如 Apache James)。
  • 验证收件箱和垃圾箱。
  1. 常见问题解决
  • 认证失败:检查用户名/密码/授权码。
  • 连接超时:确认主机/端口,检查网络。
  • 乱码:统一使用 UTF-8,编码主题/内容。
  • 附件丢失:确保文件路径正确,权限允许。

7. 完整示例:注册确认邮件

假设用户注册后发送确认邮件。

RegisterServlet

import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.IOException;
import java.util.Properties;

public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");

        String email = request.getParameter("email");
        String username = request.getParameter("username");

        // 邮件配置(同上)
        final String from = "your_email@qq.com";
        final String password = "your_auth_code";
        Properties props = new Properties();
        // ... 配置 props(如上)

        Session session = Session.getInstance(props, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(from, password);
            }
        });

        try {
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from));
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email));
            message.setSubject(MimeUtility.encodeText("注册确认", "UTF-8", "B"));
            message.setContent("<h1>欢迎," + username + "!</h1><p>您的注册已成功。</p>", "text/html;charset=UTF-8");

            Transport.send(message);
            response.getWriter().write("注册成功,确认邮件已发送!");
        } catch (Exception e) {
            response.getWriter().write("邮件发送失败:" + e.getMessage());
        }
    }
}

说明

  • 从表单获取邮箱和用户名,发送 HTML 确认邮件。
  • 支持中文用户名和主题。

8. 总结

  • Servlet 通过 JavaMail API 发送邮件,核心是配置 Session、创建 Message 和 Transport 发送。
  • 处理中文时,使用 UTF-8 编码和 MimeUtility
  • 注意安全、性能和异常处理,适合用于通知类功能。
  • 对于高级需求,可扩展到带附件或模板引擎(如 FreeMarker 生成 HTML 内容)。

如果需要更多细节(如带附件的完整代码、与其他技术的整合),或调试特定问题,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注