504 5.5.2 <NTOMSV13>: Helo command rejected: need fully-qualified hostname 问题解决方法。

本文记录了一次因邮件服务器配置不当导致的邮件发送失败问题排查及解决方案,涉及到SMTP配置、主机名验证等关键技术细节。

前言

这两天公司的项目所绑定公司的邮件服务器挂了,导致所有有关邮件的信息都发送不了,实施叫我改成另一台,并发给我了一些相关信息,修改完配置信息后,在生产环境跑了下,果然没有那么走运直接通,又因为这是项目是公司私服,只能通过公司电脑连接公司wifi才能访问,而且公司wifi又设置了白名单,除了公司的电脑其他的都无法连接,公司电脑配置又垃圾了,导致又不能在公司电脑进行开发,邮件服务器也是公司内网才能telnet,导致这排查又增添了难度。。

BUG

查看生产环境的日志,其报的错为:

	at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1294)
	at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:635)
	at javax.mail.Transport.send0(Transport.java:189)
	at javax.mail.Transport.send(Transport.java:118)
	at com.pccw.kernel.service.MessageUtil.sendEmail(MessageUtil.java:192)
	at com.pccw.kernel.service.MessageUtil.sendMessage(MessageUtil.java:368)
	at com.pccw.business.timedtask.TaskTest.sendEmail(TaskTest.java:145)
	at com.pccw.business.timedtask.TaskTest.execute(TaskTest.java:42)
	at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557)
****************Invalid Addresses

抛出的是SendFailedException这个异常,message又是 Invalid Addresses,我查了下网上所说这个错误无非就是说收件人地址无效啥啥啥的,我说这就离谱原来地址没改不也好好的,况且我自己的邮箱还能看不出来输没输错吗,后来发现原来SMTP那边会提示更详细的信息,我这边log的信息过于模糊,那好吧,只能找负责SMTP这边的同事拿log,上面提示就是如下:

Jun 28 11:17:43 mail postfix/smtpd[31147]: NOQUEUE: reject: RCPT from dcnm3.pbase.net[xxx.xxx.xxx.xxx]: 504 5.5.2 <lxcrp>: Helo command rejected: need fully-qualified hostname; from=<xx@xx.com> to=<sxxx@xx.com> proto=SMTP helo=<lxcrp>

说是我helo不符合他们的规则啥啥啥的,然后又开始巴拉巴拉的找,很多信息就是说叫我改smtp服务器main.cf文件中的接收人,发送人的规则,好家伙,我这想说我也想改啊,但是我做不到啊,可怜如我们只能遵循设定好的规则,而不能去创造规则,好吧,那只能换一种方式来排查。

排查

先用ssh连上项目所在的linux系统上再用telnet 连接smtp 服务器的25端口,如果这一步都无法成功,那能发邮件才是见鬼了。

在这里插入图片描述
一些私密信息就不方便公布出来了,可以从图片看出来这个可以正常发送邮件并能成功接收的,那就说明所给的信息是没问题的,那就应该是javamail中出了问题。看了下公司封装的jar包,结合命令行与报错日志结合,才发现helo不同导致的问题。

解决方法

javamail这东西很神奇哈,如果你没有设置其,那他就传的是你的主机名默认方法为InetAddress.getLocalHost().getHostName(),如果smtp没有配置该主机名为helo,那他就会报504,然而我这样的底层,也不能叫他们把我这主机名加到helo中去呀,那只能改成符合他这个规范的模式,即传一个自定义的helo过去。
代码如下::

System.setProperty("mail.smtp.localhost","heloName");

这个是直接将相关属性添加到JVM环境中,这样添加的方式一旦重启服务器就会丢失,也可以在发邮件的时候先获取所有系统属性的对象,然后往对象中添加也行,代码如下:

	//获取系统Properties
			Properties props = System.getProperties();		
			//设置自定义helo     
			props.setProperty("mail.smtp.localhost","heloName");  

因为我这公司的sendMessage已经封装成jar包,又没提供mail.smtp.localhost这个参数,所以肯定不能使用第二种方法了,然后第一种方法如果写在单独某个方法中,那修改量就比较大了,最后还是打算写一个Init-Method,我这个项目是使用Spring IOC作为Bean管理容器,那么可以指定init-method,其中init-method表示bean加载成功后,立即执行某个方法。

 <bean class="com.business.bcase.service.PortalBcaseHeadService" init-method="startMethod">
        <property name="portalBcaseHeadDAO">
          <ref bean="portalBcaseHeadDAO"/>
        </property>
  </bean>
public void startMethod(){
		Properties props= System.getProperties();
		if(!COMMON.isEmpty(props)){
		String localhost=props.getProperty("mail.smtp.localhost");
			
			if(COMMON.isEmpty(localhost)){
				if(!COMMON.isEmpty(SystemProperties.get("mail.smtp.localhost"))){
					System.setProperty("mail.smtp.localhost",SystemProperties.get("mail.smtp.localhost"));
				}
			}
		}
	}

改完这些之后,在测试,就成功了。
在这里插入图片描述

如果添加 `junit-jupiter-engine` 依赖后导致测试无法运行,而移除后反而能正常运行,通常是由于 **依赖配置不完整** 或 **版本冲突** 导致的。以下是详细分析和解决方案: --- ### **1. 问题原因** #### **(1) 依赖不完整** - JUnit 5 需要 **两个核心模块** 才能正常运行: - `junit-jupiter-api`:提供测试注解和断言(如 `@Test`、`Assertions`)。 - `junit-jupiter-engine`:提供测试引擎,用于实际执行测试。 - **如果只添加 `junit-jupiter-engine` 而没有 `junit-jupiter-api`**,可能会导致测试类无法编译或运行时找不到方法。 #### **(2) 版本冲突** - 如果项目中其他依赖(如 Spring Boot Starter Test)引入了 **不同版本的 JUnit 5**,可能会导致类加载冲突。 - 例如: - `spring-boot-starter-test` 默认引入 JUnit 5.8.x,而手动添加了 5.5.2,导致版本不兼容。 #### **(3) 构建工具配置问题** - Maven/Gradle 的测试插件(如 Surefire)未正确配置,无法识别 JUnit 5 引擎。 --- ### **2. 解决方案** #### **方案 1:补全 JUnit 5 依赖(推荐)** 确保同时包含 `junit-jupiter-api` 和 `junit-jupiter-engine`,且版本一致: ```xml <properties> <junit.jupiter.version>5.8.2</junit.jupiter.version> <!-- 推荐使用 Spring Boot 默认版本 --> </properties> <dependencies> <!-- JUnit 5 API(提供注解和断言) --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.jupiter.version}</version> <scope>test</scope> </dependency> <!-- JUnit 5 引擎(用于运行测试) --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.jupiter.version}</version> <scope>test</scope> </dependency> </dependencies> ``` #### **方案 2:通过 Spring Boot 管理版本** 如果使用 Spring Boot,建议通过 `spring-boot-starter-test` 管理 JUnit 版本(避免手动指定): ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <!-- 排除旧版 JUnit 4(如果需要) --> <exclusions> <exclusion> <groupId>junit</groupId> <artifactId>junit</artifactId> </exclusion> </exclusions> </dependency> ``` Spring Boot 默认会引入兼容的 JUnit 5 版本(如 5.8.2)。 #### **方案 3:检查构建插件配置** 确保 Maven Surefire 插件支持 JUnit 5: ```xml <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> <!-- 最低要求 2.22.0 --> </plugin> </plugins> </build> ``` --- ### **3. 验证是否解决** 1. **清理并重新构建**: ```bash mvn clean test ``` 2. **检查依赖树**: ```bash mvn dependency:tree | grep junit ``` 确保没有多个冲突版本(如 5.5.25.8.x 混用)。 3. **观察测试运行日志**: - 正常情况应看到类似: ``` Running com.example.MyTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 ``` - 如果报错 `No tests found`,可能是引擎未正确加载。 --- ### **4. 常见问题** #### **Q1: 为什么只加 `junit-jupiter-engine` 会导致问题?** - `junit-jupiter-engine` 仅包含运行时引擎,不包含编译时需要的 API(如 `@Test` 注解)。缺少 API 会导致测试类编译失败或运行时找不到方法。 #### **Q2: 如何排查依赖冲突?** - 使用 `mvn dependency:tree -Dverbose` 查看所有依赖的来源。 - 重点关注 `org.junit.jupiter` 相关的库是否有多个版本。 #### **Q3: IDE 中测试显示灰色(未识别)?** - 检查 IDE 的 JUnit 库配置: - **IntelliJ**:`File > Project Structure > Modules > Dependencies`。 - **Eclipse**:右键项目 > `Build Path > Configure Build Path`。 - 确保 IDE 使用的是 Maven/Gradle 管理的依赖,而非本地单独添加的 JAR。 #### **Q4: 为什么移除 `junit-jupiter-engine` 后测试能运行?** - 如果项目中其他依赖(如 `spring-boot-starter-test`)已经隐式引入了 JUnit 5 引擎,手动添加旧版本可能导致冲突。移除后可能回退到隐式引入的正确版本。 --- ### **5. 总结** | 问题表现 | 根本原因 | 解决方案 | |----------|----------|----------| | 添加 `junit-jupiter-engine` 后测试找不到 | 依赖不完整或版本冲突 | 补全 `junit-jupiter-api` 并统一版本 | | 测试类编译失败(如 `@Test` 报错) | 缺少 API 依赖 | 添加 `junit-jupiter-api` | | 运行时提示 `No tests found` | 引擎未正确加载 | 检查 Surefire 插件版本 | **关键点**: - JUnit 5 需要 **API + 引擎** 两个模块。 - 优先通过 `spring-boot-starter-test` 管理版本,避免手动指定。 - 使用 `dependency:tree` 定位冲突。 --- ### **
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值