Spring JavaMailSender与Testcontainers Mailpit集成失败排查
问题分析与解决:Testcontainers中Mailpit邮件发送失败
问题场景
测试环境通过Testcontainers运行Mailpit实例:
@Container static MailpitContainer mailpitContainer = new MailpitContainer() .withNetwork(TESTCONTAINERS_NETWORK);
被测服务本身也部署在Testcontainers实例中:
public class MyServiceUnderTestContainer extends GenericContainer<ArgusBatchContainer> { private static final String IMAGE_NAME... static { Testcontainers.exposeHostPorts(1025); } public MyServiceUnderTestContainer(Map<String, String> environmentVariables) { super(IMAGE_NAME); this.withAccessToHost(true); this.withNetwork(TESTCONTAINERS_NETWORK); } }
Spring JavaMailSender配置如下:
@Bean public JavaMailSenderImpl createJavaMailSenderBean() { final JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); mailSender.setHost("host.testcontainers.internal"); mailSender.setPort(1025); mailSender.setUsername(""); mailSender.setPassword(null); mailSender.setProtocol("smtp"); mailSender.setJavaMailProperties(createJavaMailProperties()); return mailSender; } private Properties createJavaMailProperties() { final Properties properties = new Properties(); properties.put("mail.smtp.auth", false); properties.put("mail.smtp.starttls.enable", false); properties.put("mail.smtp.connectiontimeout", 180000); properties.put("mail.smtp.timeout", 180000); return properties; }
运行时出现如下错误:
org.springframework.mail.MailSendException: Mail server connection failed. Failed messages: jakarta.mail.MessagingException: Got bad greeting from SMTP host: host.testcontainers.internal, port: 1025, response: [EOF]
错误原因
- 访问目标错误:
host.testcontainers.internal指向Testcontainers宿主机,但Mailpit容器运行在Testcontainers内部的TESTCONTAINERS_NETWORK网络中,并未将1025端口映射到宿主机,导致服务容器访问宿主机1025端口时无任何响应,返回EOF。 - 冗余操作干扰:被测服务容器中的
Testcontainers.exposeHostPorts(1025);完全多余,Mailpit不在宿主机运行,该操作不仅无效,还可能造成端口逻辑混淆。
解决方法
1. 通过容器内部网络访问Mailpit
由于Mailpit容器和被测服务容器同属TESTCONTAINERS_NETWORK网络,可直接使用Mailpit容器的名称或自定义别名作为SMTP主机地址:
- 方法一:直接传递Mailpit容器名称
修改JavaMailSender的主机配置:mailSender.setHost(mailpitContainer.getContainerName()); mailSender.setPort(1025); // 容器内部默认SMTP端口 - 方法二:给Mailpit设置固定网络别名
先给Mailpit容器配置固定别名:
然后在JavaMailSender中使用该别名:@Container static MailpitContainer mailpitContainer = new MailpitContainer() .withNetwork(TESTCONTAINERS_NETWORK) .withNetworkAliases("mailpit"); // 设置固定别名mailSender.setHost("mailpit"); mailSender.setPort(1025); - 方法三:通过环境变量传递配置(推荐,解耦代码与配置)
构建被测服务容器时传入Mailpit连接信息:
再在JavaMailSender配置中读取环境变量:Map<String, String> env = new HashMap<>(); env.put("MAIL_HOST", mailpitContainer.getContainerName()); env.put("MAIL_PORT", "1025"); MyServiceUnderTestContainer serviceContainer = new MyServiceUnderTestContainer(env);mailSender.setHost(System.getenv("MAIL_HOST")); mailSender.setPort(Integer.parseInt(System.getenv("MAIL_PORT")));
2. 移除冗余的端口暴露代码
删除被测服务容器中的静态代码块:
// 移除该冗余代码 static { Testcontainers.exposeHostPorts(1025); }
3. 验证网络连通性(可选)
可在被测服务容器内执行以下命令,验证与Mailpit的网络连通性:
telnet mailpit 1025 # 或使用nc命令 nc -zv mailpit 1025
若能成功连通,说明网络配置正确。
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

