SMTP 之 Java 调用示例
时间:2025-07-31 17:20:12 作者:阿里邮箱企业版 来源:阿里邮箱本文介绍使用 Javamail 通过 SMTP 协议发信。
<dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version></dependency><dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version></dependency><dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version></dependency>
示例代码
package org.example;import javax.mail.*;import javax.mail.internet.*;import java.io.UnsupportedEncodingException;//import java.net.MalformedURLException;import java.util.Date;import java.util.Properties;import java.util.UUID;//import java.util.HashMap;//import java.util.Base64;//import java.net.URL;//import java.io.IOException;//import java.io.InputStream;//import javax.mail.util.ByteArrayDataSource;//import java.net.URLEncoder;//import javax.activation.DataHandler;//import javax.activation.FileDataSource;//import javax.activation.URLDataSource;//import com.google.gson.GsonBuilder;public class SampleMail { // 配置常量
private static final String SMTP_HOST = "smtpdm.aliyun.com"; private static final int SMTP_PORT = 80; private static final String USER_NAME = "发信地址"; private static final String PASSWORD = "xxxxxxx"; protected static String genMessageID(String mailFrom) { // 生成Message-ID:
if (!mailFrom.contains("@")) { throw new IllegalArgumentException("Invalid email format: " + mailFrom);
} String domain = mailFrom.split("@")[1]; UUID uuid = UUID.randomUUID(); return "<" + uuid.toString() + "@" + domain + ">";
} private static void setRecipients(MimeMessage message, Message.RecipientType type, String[] recipients)
throws MessagingException { // 设置收件人地址
if (recipients == null || recipients.length == 0) { return; // 空列表不设置
}
InternetAddress[] addresses = new InternetAddress[recipients.length]; for (int h = 0; h < recipients.length; h++) {
addresses[h] = new InternetAddress(recipients[h]);
}
message.setRecipients(type, addresses);
} public static void main(String[] args) throws MessagingException, UnsupportedEncodingException { // 配置发送邮件的环境属性
final Properties props = new Properties(); // 表示SMTP发送邮件,需要进行身份验证
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", SMTP_HOST); //设置端口:
props.put("mail.smtp.port", SMTP_PORT);//或"25", 如果使用ssl,则去掉使用80或25端口的配置,进行如下配置:
//加密方式:
//props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//props.put("mail.smtp.socketFactory.fallback", "false");//禁止回退非加密
//props.put("mail.smtp.socketFactory.port", "465");
//props.put("mail.smtp.port", "465");
props.put("mail.smtp.from", USER_NAME); //mailfrom 参数
props.put("mail.user", USER_NAME);// 发件人的账号(在控制台创建的发信地址)
props.put("mail.password", PASSWORD);// 发信地址的smtp密码(在控制台选择发信地址进行设置)
//props.put("mail.smtp.connectiontimeout", 1000);
System.setProperty("mail.mime.splitlongparameters", "false");//用于解决附件名过长导致的显示异常
//props.setProperty("mail.smtp.ssl.enable", "true"); //请配合465端口使用
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() { @Override
protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(USER_NAME, PASSWORD);
}
}; //使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator); String messageIDValue = genMessageID(USER_NAME); MimeMessage message = new MimeMessage(mailSession) { @Override
protected void updateMessageID() throws MessagingException {
setHeader("Message-ID", messageIDValue);
}
}; try { // 设置发件人邮件地址和名称。填写控制台配置的发信地址。和上面的mail.user保持一致。名称用户可以自定义填写。
InternetAddress from = new InternetAddress(USER_NAME, "发件人昵称");//from 参数,可实现代发,注意:代发容易被收信方拒信或进入垃圾箱。
message.setFrom(from);
setRecipients(message, Message.RecipientType.TO, new String[]{"收信地址1", "收信地址2"});
setRecipients(message, Message.RecipientType.CC, new String[]{"收信地址3", "收信地址4"});
setRecipients(message, Message.RecipientType.BCC, new String[]{"收信地址5", "收信地址6"}); InternetAddress replyToAddress = new InternetAddress("回信地址");
message.setReplyTo(new Address[]{replyToAddress});//可选。设置回信地址
message.setSentDate(new Date());
message.setSubject("测试主题");// message.setContent("测试txt内容1", "text/text;charset=UTF-8");//纯文本内容,若使用MimeBodyPart这里会被覆盖// 或// message.setContent("测试<br> html内容2", "text/html;charset=UTF-8");//HTML内容,若使用MimeBodyPart这里会被覆盖// //若需要开启邮件跟踪服务,请使用以下代码设置跟踪链接头。前置条件和约束见文档"如何开启数据跟踪功能?"// String tagName = "tagname4";// HashMap<String, String> trace = new HashMap<>();// //这里为字符串"1"// trace.put("OpenTrace", "1"); //打开邮件跟踪// trace.put("LinkTrace", "1"); //点击邮件里的URL跟踪// trace.put("TagName", tagName); //控制台创建的标签tagname// String jsonTrace = new GsonBuilder().setPrettyPrinting().create().toJson(trace);// //System.out.println(jsonTrace);// String base64Trace = new String(Base64.getEncoder().encode(jsonTrace.getBytes()));// //设置跟踪链接头// message.addHeader("X-AliDM-Trace", base64Trace);
//邮件eml原文中的示例值:X-AliDM-Trace: eyJUYWdOYW1lIjoiVGVzdCIsIk9wZW5UcmFjZSI6IjEiLCJMaW5rVHJhY2UiOiIxIn0=
//发送附件和内容:
// 创建多重消息
Multipart multipart = new MimeMultipart();// // 创建一个BodyPart用于纯文本内容// BodyPart textPart = new MimeBodyPart();// textPart.setText("测试txt内容3");// multipart.addBodyPart(textPart);
// 创建一个BodyPart用于HTML内容
BodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("测试<br> html内容4", "text/html;charset=UTF-8");//设置邮件的内容,会覆盖前面的message.setContent
multipart.addBodyPart(htmlPart);// //附件部分// //发送附件,总的邮件大小不超过15M,创建消息部分。// // 发送本地附件// String[] fileList = {"C:\\Users\\Downloads\\test1.txt", "C:\\Users\\Downloads\\test2.txt"};// for (String filePath : fileList) {// MimeBodyPart mimeBodyPart = new MimeBodyPart();//// FileDataSource fileDataSource = new FileDataSource(filePath);// mimeBodyPart.setDataHandler(new DataHandler(fileDataSource));// //处理附件名称中文(附带文件路径)乱码问题// mimeBodyPart.setFileName(MimeUtility.encodeWord(fileDataSource.getName()));// mimeBodyPart.addHeader("Content-Transfer-Encoding", "base64");// multipart.addBodyPart(mimeBodyPart);// }// // 发送URL附件// String[] fileListUrl = {"https://example.oss-cn-shanghai.aliyuncs.com/xxxxxxxxxxx1.png", "https://example.oss-cn-shanghai.aliyuncs.com/xxxxxxxxxxx2.png"};// for (String fileUrl : fileListUrl) {// URL url = new URL(fileUrl);// String filename = url.getPath();// filename = filename.substring(filename.lastIndexOf('/') + 1);// try (InputStream in = url.openStream()) {// // 创建附件部分// MimeBodyPart attachmentPart = new MimeBodyPart();// // 使用字节数组数据源// ByteArrayDataSource ds = new ByteArrayDataSource(in, "application/octet-stream");// attachmentPart.setDataHandler(new javax.activation.DataHandler(ds));// attachmentPart.setFileName(filename);// attachmentPart.setDisposition(MimeBodyPart.ATTACHMENT);// multipart.addBodyPart(attachmentPart);// } catch (IOException e) {// throw new RuntimeException(e);// }// }
// 添加完整消息
message.setContent(multipart); // 发送附件代码,结束
//mailSession.setDebug(true);//开启debug模式
Transport.send(message);
System.out.println("发送完成!");
} catch (MessagingException | UnsupportedEncodingException e) {
System.err.println("邮件发送失败: " + e.getMessage());
e.printStackTrace();// } catch (MalformedURLException e) {// throw new RuntimeException(e);
}
}
}常见问题
为什么收到的邮件里看到了其他收件人? 原因可能是SMTP请求时,邮件头传参中包含了其他收件人。 SMTP发信支持一次请求发送给多人(具体人数参考规格清单(单次调用支持的收件人个数)),但这种方式会导致收件人全部显示在邮件中(或者不传TO和CC字段,只传入BCC字段,这样可能因为收信方反垃圾策略被拒收,不推荐),适合一封邮件多人参与的场景,Message-ID通常是同一个。 还有一种场景是要求各自收到,不要被其他人看到收件人,需要分开请求,比如,发送6人就请求6次(SMTP发信支持并发请求),每次请求相当于一封独立邮件,Message-ID通常不是同一个。
