You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Amazon SES sendRawEmail发邮件仅BCC生效,TO/CC失效求解决

SES SendRawEmail仅BCC能发送,TO/CC失败的排查与解决

我在使用Amazon SES的sendRawEmail接口发送邮件时遇到异常:只有当收件人在BCC邮件头时能成功发送,TO或CC字段包含收件人时完全发不出去。查了官方文档也没找到原因,附上我的代码,求帮忙排查:

public void send(Payload request) throws MessagingException, IOException {
    List<String> recipients = new LinkedList<>();

    String from = request.getFrom();
    String targetEmail = request.getRecipient();
    String ccEmail = request.getCc();
    String bccEmail = request.getBcc();

    Session session = Session.getDefaultInstance(new Properties());
    MimeMessage message = new MimeMessage(session);

    message.setSubject(request.getSubject());
    message.setFrom(new InternetAddress(from));
    if (targetEmail != null) {
        message.setRecipients(RecipientType.TO, InternetAddress.parse(targetEmail));
        recipients.add(targetEmail);
    }
    if (ccEmail != null) {
        message.setRecipients(RecipientType.CC, InternetAddress.parse(ccEmail));
        recipients.add(ccEmail);
    }
    if (bccEmail != null) {
        message.setRecipients(RecipientType.BCC, InternetAddress.parse(bccEmail));
        recipients.add(bccEmail);
    }
    MimeBodyPart htmlPart = new MimeBodyPart();
    htmlPart.setContent(request.getBody(), "text/html; charset=UTF-8;");

    MimeMultipart bodyContainer = new MimeMultipart("alternative");
    bodyContainer.addBodyPart(htmlPart);

    MimeBodyPart htmlWrapper = new MimeBodyPart();
    htmlWrapper.setContent(bodyContainer);

    MimeMultipart messageContainer = new MimeMultipart("mixed");
    messageContainer.addBodyPart(htmlWrapper);

    Attachment attachment = request.getAttachment();
    if (Objects.nonNull(attachment)) {
        MimeBodyPart attachmentBodyPart = new MimeBodyPart();
        DataHandler dataHandler = new DataHandler(attachment.getByteArrayDataSource());

        attachmentBodyPart.setDataHandler(dataHandler);
        attachmentBodyPart.setFileName(attachment.getFileName());

        messageContainer.addBodyPart(attachmentBodyPart);
    }

    message.setContent(messageContainer);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    message.writeTo(outputStream);

    RawMessage rawMessage = new RawMessage(ByteBuffer.wrap(outputStream.toByteArray()));

    SendRawEmailRequest rawEmailRequest = new SendRawEmailRequest(rawMessage);
    rawEmailRequest.withSource(from);
    rawEmailRequest.withDestinations(recipients);

    SendRawEmailResult sendRawEmailResult = amazonSimpleEmailService.sendRawEmail(rawEmailRequest);
    log.info("Email sent. MessageId: {}", targetEmail, ccEmail, bccEmail, sendRawEmailResult.getMessageId());
}

核心问题分析

你的代码存在两个关键问题,直接导致TO/CC收件人无法正常发送:

  1. 收件人列表格式错误
    当targetEmail或ccEmail是多个用逗号分隔的邮箱地址时,InternetAddress.parse()能正确解析为多个InternetAddress对象,但你直接把原始的带逗号的字符串(比如"a@xx.com,b@xx.com")添加到recipients列表中。而SES的withDestinations()要求列表中的每个元素都是单个有效的邮箱地址,不是带分隔符的字符串。这种情况下,TO/CC对应的地址会被SES判定为无效邮箱,导致发送失败;如果你的BCC只传单个邮箱,就不会触发这个问题。

  2. SendRawEmail参数逻辑冲突
    使用sendRawEmail时,如果你指定了Destinations参数,SES会忽略邮件头中的TO/CC/BCC信息,直接使用这个参数里的地址作为收件人。你同时在邮件头设置了TO/CC,又把这些地址加到Destinations,虽然逻辑上看似一致,但格式错误的Destinations列表会直接导致TO/CC的地址无法被正确识别。


修复方案

1. 正确拆分收件人到列表

不要直接添加原始字符串,而是将InternetAddress.parse()返回的地址逐个提取出来加入recipients:

// 替换原有的TO/CC/BCC处理逻辑
if (targetEmail != null) {
    InternetAddress[] toAddresses = InternetAddress.parse(targetEmail);
    message.setRecipients(RecipientType.TO, toAddresses);
    for (InternetAddress addr : toAddresses) {
        recipients.add(addr.getAddress());
    }
}
if (ccEmail != null) {
    InternetAddress[] ccAddresses = InternetAddress.parse(ccEmail);
    message.setRecipients(RecipientType.CC, ccAddresses);
    for (InternetAddress addr : ccAddresses) {
        recipients.add(addr.getAddress());
    }
}
if (bccEmail != null) {
    InternetAddress[] bccAddresses = InternetAddress.parse(bccEmail);
    message.setRecipients(RecipientType.BCC, bccAddresses);
    for (InternetAddress addr : bccAddresses) {
        recipients.add(addr.getAddress());
    }
}

2. 可选优化:移除Destinations参数(推荐)

如果你已经在原始邮件中正确设置了TO/CC/BCC头,可以直接移除withDestinations()的调用。SES会自动解析原始邮件中的收件人信息,这样能避免参数和邮件头的冲突:

SendRawEmailRequest rawEmailRequest = new SendRawEmailRequest(rawMessage);
rawEmailRequest.withSource(from);
// 移除这一行:rawEmailRequest.withDestinations(recipients);

额外排查点

  • 确认发件地址from已经在SES控制台完成验证(邮箱或域名验证),SES不允许发送未验证的发件地址。
  • 确认TO/CC的收件人地址没有被SES列入黑名单,且如果是发送到外部邮箱,你的SES账户已经移出沙箱(沙箱环境下只能发送到已验证的收件人)。

内容的提问来源于stack exchange,提问作者N. G.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 09:05:23