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

前言

这两天公司的项目所绑定公司的邮件服务器挂了,导致所有有关邮件的信息都发送不了,实施叫我改成另一台,并发给我了一些相关信息,修改完配置信息后,在生产环境跑了下,果然没有那么走运直接通,又因为这是项目是公司私服,只能通过公司电脑连接公司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"));
				}
			}
		}
	}

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Java 8中的Stream API和CSV库来实现将List<ADto>输出成CSV文件的功能。 首先,需要添加CSV库的依赖。这里以OpenCSV为例,在Maven项目中添加以下依赖: ```xml <dependency> <groupId>com.opencsv</groupId> <artifactId>opencsv</artifactId> <version>5.5.2</version> </dependency> ``` 然后,可以编写一个方法,接受List<ADto>、ADto.class和filePath作为参数,实现将数据输出成CSV文件的功能。代码如下: ```java import com.opencsv.CSVWriter; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; import java.util.List; import java.util.stream.Collectors; public class CsvUtil { public static <T> void writeCsv(List<T> dataList, Class<T> clazz, String filePath) { try (CSVWriter writer = new CSVWriter(new FileWriter(filePath))) { // 获取类的所有字段 Field[] fields = clazz.getDeclaredFields(); // 获取字段名数组 String[] headers = getFieldNames(fields); // 写入表头 writer.writeNext(headers); // 写入数据 List<String[]> data = dataList.stream() .map(t -> getFieldValues(t, fields)) .collect(Collectors.toList()); writer.writeAll(data); } catch (IOException e) { e.printStackTrace(); } } // 获取字段名数组 private static String[] getFieldNames(Field[] fields) { return Stream.of(fields) .map(Field::getName) .toArray(String[]::new); } // 获取字段值数组 private static <T> String[] getFieldValues(T t, Field[] fields) { return Stream.of(fields) .map(f -> { try { f.setAccessible(true); return String.valueOf(f.get(t)); } catch (IllegalAccessException e) { e.printStackTrace(); return ""; } }) .toArray(String[]::new); } } ``` 这个方法使用了Java 8的Stream API来处理列表数据,使用反射获取类的字段名和字段值。在写入CSV文件时,需要使用CSVWriter类来处理。 使用示例: ```java List<ADto> dataList = ... CsvUtil.writeCsv(dataList, ADto.class, "output.csv"); ``` 这样,就可以将数据输出成CSV文件了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值