使用TestContainers部署Apache James遇SMTP端口连接拒绝求助
Apache James TestContainers 连接拒绝问题解决
问题场景
通过TestContainers运行Apache James容器,等效于以下Docker命令:
docker run --name james_run -p "25:25" -p "465:465" -p "587:587" -p "143:143" -p "993:993" --volume "$PWD/conf:/root/conf/" --volume "$PWD/var:/root/var/" apache/james:latest
对应的TestContainers代码:
james = new GenericContainer(DockerImageName.parse("apache/james")).withExposedPorts(25, 465, 587, 143, 993, 8000).withFileSystemBind(EmailServerIT.class.getClassLoader().getResource("conf").getPath(),"/root/conf", BindMode.READ_WRITE).withFileSystemBind(EmailServerIT.class.getClassLoader().getResource("var").getPath(),"/root/var", BindMode.READ_WRITE);
尝试向SMTP端口发送邮件时出现连接拒绝错误:
Caused by: javax.mail.MessagingException: Connection error (java.net.ConnectException: Connection refused (Connection refused))
解决方案
1. 修正端口映射逻辑
TestContainers不会直接绑定主机固定端口,而是采用随机端口映射。不能直接使用25/587等原始端口,需通过getMappedPort()获取容器映射到主机的实际端口:
// 获取SMTP提交端口的实际映射端口 int smtpPort = james.getMappedPort(587); // 发送邮件时使用该端口连接 Properties props = new Properties(); props.put("mail.smtp.port", smtpPort);
2. 修复资源路径绑定问题
ClassLoader.getResource("conf")可能返回Jar包内的路径,TestContainers无法直接挂载。改用withClasspathResourceMapping简化classpath资源挂载,或使用正确的本地文件路径:
// 推荐:直接挂载classpath中的资源目录 james = new GenericContainer(DockerImageName.parse("apache/james:latest")) .withExposedPorts(25, 465, 587, 143, 993, 8000) .withClasspathResourceMapping("conf", "/root/conf", BindMode.READ_WRITE) .withClasspathResourceMapping("var", "/root/var", BindMode.READ_WRITE);
若必须使用withFileSystemBind,需确保资源路径指向本地文件系统:
Path confPath = Paths.get(EmailServerIT.class.getResource("/conf").toURI()); Path varPath = Paths.get(EmailServerIT.class.getResource("/var").toURI()); james = new GenericContainer(DockerImageName.parse("apache/james:latest")) .withExposedPorts(25, 465, 587, 143, 993, 8000) .withFileSystemBind(confPath.toString(), "/root/conf", BindMode.READ_WRITE) .withFileSystemBind(varPath.toString(), "/root/var", BindMode.READ_WRITE);
3. 添加容器就绪检查
Apache James启动需要一定时间,需等待服务完全就绪后再发起连接:
james = new GenericContainer(DockerImageName.parse("apache/james:latest")) // 其他配置... .waitingFor(Wait.forLogMessage(".*James server is ready.*", 1) .withStartupTimeout(Duration.ofMinutes(2)));
4. 验证配置文件有效性
检查挂载的conf目录下配置:
- 确保
smtpserver.xml开启了非SSL端口(25/587),未强制要求SSL认证 - 若使用SSL端口(465),需确保配置了正确的密钥库,或在测试环境下允许自签名证书
内容的提问来源于stack exchange,提问作者ca55idy
相关产品推荐
相关产品推荐

