Java17+SpringBoot3.0.6部署K8s时JavaMailSender无法解析SMTP主机名
问题:Java17+SpringBoot3部署在AWS EKS 1.24后无法通过SMTP主机名发送邮件
背景
我们正在将Java服务从Java11+SpringBoot2.7.1迁移至Java17+SpringBoot3.0.6,通过Docker镜像部署到AWS Kubernetes 1.24(EKS)环境。原版本可正常发送邮件,但升级后使用SMTP主机名时出现连接失败错误。
关键现象
- 使用SMTP服务器IP地址时,Java17+SpringBoot3.0.6版本可正常工作
- 本地IDE中,两个版本使用主机名或IP均能正常发送邮件
- 将代码打包为Jar在AWS虚拟机(EC2)上运行Java17版本,使用主机名也可正常触发邮件
- 仅在EKS环境中部署Docker镜像后,使用SMTP主机名会抛出
UnknownHostException
邮件发送报错日志
12:46:48 DEBUG SMTP: trying to connect to host "company smpt host", port 25, isSSL false 12:46:48 ("timestamp":"07-03-2023 GMT 07:14:19.672","level": "ERROR", "thread":"http-nio-8081-exec-6", "logger":"com.emailer.service.FreeMarkerEMailSevice", "message":"Email sending failed with exception : {}","context":"default", "exception":"com.sun.mail.util.MailConnectException: Couldn't connect to host, port: <company.smtpserver.com>, 5000 at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2259) at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:754) at jakarta.mail.Service.connect(Service.java:342) at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:518) at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:437) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:361) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:356) ... java.net.UnknownHostException: <company smtp host> at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567) at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:331) at java.base/java.net.Socket.connect(Socket.java:630) at com.sun.mail.util.WriteTimeoutSocket.connect(WriteTimeoutSocket.java:104) at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:355)
主机名解析报错日志
12:45:48 {"timestamp":"07-03-2023 GMT 07:16:35.225","level":"ERROR", "thread":"http-nio-8081-exec-7","logger":"com.emailer.service.FreeMarkerEMailSevice", "message":"error occurred while trying to get ipaddress <company smtp server>","context":"default"} 12:46:48 {"timestamp":"07-03-2023 GMT 07:16:35.226","level":"ERROR", "thread":"http-nio-8081-exec-7","logger":"org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]", "message":"Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.RuntimeException: java.net.UnknownHostException <company smtp server>: Try again] with root cause", "context":"default", "exception":"java.net.UnknownHostException: <company smtp server>: Try again at java.base/java.net.InetAddressImpl.lookupAllHostAddr(Native Method) at java.base/java.net.InetAddress$PlatformNameService.lookupAllHostAddr(InetAddress.java:932) at java.base/java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1517) at java.base/java.net.InetAddress$ServiceAddresses.get(InetAddress.java:851) at java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1587) at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1366) at java.base/java.net.InetAddress.getAllByName(InetAddress.java:1300) at java.base/java.net.InetAddress.getByName(InetAddress.java:1250) ...
应用配置(application.yaml)
spring.mail.host = <company smtpserver> spring.mail.port= 25 spring.mail.username = xxxxx spring.mail.password = xxxx spring.mail.properties.mail.smtp.auth = true; spring.mail.properties.mail.smtp.starttls.enable = true spring.mail.properties.mail.transport.protocol = smtp spring.mail.properties.mail.smtp.timeout = 5000
核心代码
@Service public class EmailService{ private JavaMailSender emailSender; public EmailService(JavaMailSender emailSender){ this.emailSender = emailSender; } @Override public void sendEmail(MailModel mailModel) { MimeMessage message = emailSender.createMimeMessage(); try{ MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(message,true); Template template = emailConfig.getTemplate("email4.ftl"); String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, mailModel.getModel()); mimeMessageHelper.setTo(mailModel.getTo()); mimeMessageHelper.setText(html, true); mimeMessageHelper.setSubject(mailModel.getSubject()); mimeMessageHelper.setFrom(mailModel.getFrom()); emailSender.send(mimeMessageHelper.getMimeMessage()); }catch(Exception e){ log.error("exception occurred {}", e.getCause()); } } }
解决方案
1. 检查EKS Pod的DNS配置
- 确认EKS集群CoreDNS组件运行正常:
kubectl get pods -n kube-system -l k8s-app=kube-dns - 进入问题Pod直接测试DNS解析:
如果解析失败,检查Pod的kubectl exec -it <你的Pod名称> -- nslookup <公司SMTP服务器主机名>dnsPolicy是否为默认的ClusterFirst,是否存在自定义dnsConfig覆盖了默认配置。
2. 调整Java17的DNS缓存策略
Java17默认DNS缓存时长比Java11更长,可能导致无法及时获取最新DNS记录。在JVM启动参数中添加以下配置缩短缓存时间:
-Dsun.net.inetaddr.ttl=60 -Dsun.net.inetaddr.negative.ttl=10
sun.net.inetaddr.ttl:正向DNS记录缓存时长(单位:秒)sun.net.inetaddr.negative.ttl:失败DNS记录缓存时长(单位:秒)
3. 验证Docker镜像与Pod的DNS配置
- 确保Docker镜像未自定义DNS配置,构建时不要添加
--dns参数 - 若需要,可在Kubernetes的Pod Spec中显式指定DNS服务器:
spec: containers: - name: 你的应用名称 image: 你的镜像地址:版本 dnsPolicy: ClusterFirst dnsConfig: nameservers: - 8.8.8.8 - 1.1.1.1
4. 检查VPC网络与私有DNS配置
如果SMTP服务器是AWS内部服务或企业私有服务:
- 确认EKS集群所在VPC与SMTP服务器所在VPC已建立对等连接
- 检查是否配置了正确的私有DNS区域,确保Pod能解析内部主机名
5. 临时规避方案
若以上方法暂时无法解决,可先在配置中使用SMTP服务器IP地址(已验证可行),同时联系运维团队排查DNS根因。
内容的提问来源于stack exchange,提问作者Vikneshwar Vikki
相关产品推荐
相关产品推荐

