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

使用BouncyCastle发送S/MIME加密邮件遇实例类型异常求助

S/MIME加密邮件发送异常排查与解决

问题描述

发送S/MIME加密邮件时持续抛出以下异常:

javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.IOException: javax.mail.MessagingException: Cannot write this object. It has to be an instance of iaik.security.smime.EncryptedContent or iaik.security.smime.SignedContent!

环境与操作细节

  • 使用Bouncy Castle作为安全提供者:测试输出显示版本v1.69,实际引入1.71的jdk18on-171系列包
  • 参照org.bouncycastle.mail.smime.examples.CreateEncryptedMail编写代码,额外操作:
    • 从文件读取证书
    • 配置Mailcap:
      private void setDefaultMailcap() {
          final MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
          mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
          mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
          mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
          mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
          mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
          CommandMap.setDefaultCommandMap(mailcap);
      }
      
    • 配置SMTP服务器:
      props.put("mail.smtp.host", host);
      props.put("mail.smtp.port", port);
      
      Session session = Session.getInstance(props,
        new Authenticator() {
           protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
              return new javax.mail.PasswordAuthentication(user, password);
           }
        });
      
    • 发送代码:
      final Transport transport = session.getTransport("smtp");
      transport.send(body);
      
  • 依赖库:activation.jar、bcmail-jdk18on-171.jar、bcpkix-jdk18on-171.jar、bcprov-ext-jdk18on-171.jar、bcprov-jdk18on-171.jar、bcutil-jdk18on-171.jar、commons-codec-1.15.jar、commons-io-2.11.0.jar、junit.jar、mail.jar

完整异常栈

javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.IOException: javax.mail.MessagingException: Cannot write this object. It has to be an instance of iaik.security.smime.EncryptedContent or iaik.security.smime.SignedContent!
com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1350)
javax.mail.Transport.send0(Transport.java:231)
javax.mail.Transport.send(Transport.java:100)


问题根源与解决办法

1. 移除IAIK库依赖或残留

异常中提到的iaik.security.smime类属于IAIK S/MIME库,而非Bouncy Castle。说明项目或运行环境中存在IAIK相关组件,导致JavaMail优先使用了IAIK的内容处理器。

  • 检查项目依赖,删除所有IAIK相关jar包(如iaik_jce.jar、iaik_smime.jar等)
  • 检查JRE的lib/ext目录,移除其中的IAIK文件
  • 用依赖管理工具(Maven/Gradle)排查并排除间接引入的IAIK依赖

2. 重构Mailcap配置,避免原有配置干扰

修改Mailcap配置逻辑,新建命令映射而非修改默认实例,确保Bouncy Castle处理器优先级最高:

private void setDefaultMailcap() {
    // 新建MailcapCommandMap,彻底替换原有配置
    MailcapCommandMap mailcap = new MailcapCommandMap();
    mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
    mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
    mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
    mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
    mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
    CommandMap.setDefaultCommandMap(mailcap);
}

3. 优先注册Bouncy Castle安全提供者

在代码启动阶段将Bouncy Castle注册为最高优先级的安全提供者:

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;

// 在应用初始化时执行
Security.insertProviderAt(new BouncyCastleProvider(), 1);

4. 确认加密对象类型为Bouncy Castle实现

确保加密后的邮件对象使用Bouncy Castle的SMIMEEnveloped生成,而非IAIK类型。示例流程:

// 创建原始MimeMessage
MimeMessage originalMsg = new MimeMessage(session);
originalMsg.setFrom(new InternetAddress(sender));
originalMsg.setRecipient(Message.RecipientType.TO, new InternetAddress(recipient));
originalMsg.setSubject("S/MIME Encrypted Test");
originalMsg.setText("Test content");

// 使用Bouncy Castle生成加密内容
SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator();
gen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("BC"));
MimeBodyPart encryptedPart = gen.generate(originalMsg, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC).setProvider("BC").build());

// 封装为可发送的MimeMessage
MimeMessage encryptedMsg = new MimeMessage(session);
encryptedMsg.setContent(encryptedPart.getContent(), encryptedPart.getContentType());
encryptedMsg.setHeader("Content-Disposition", "attachment; filename=\"encrypted.msg\"");

// 发送加密后的消息
transport.send(encryptedMsg);

5. 清理旧版本Bouncy Castle残留

测试输出显示版本v1.69但实际引入1.71,说明存在旧版本BC包:

  • 检查项目依赖,排除所有低于1.71版本的BC组件
  • 检查应用服务器/容器的类路径,删除旧版本BC jar

内容的提问来源于stack exchange,提问作者user20144981

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 00:45:27