java socket 连接邮箱_Java与邮件系统交互之使用Socket验证邮箱是否存在

这篇博客介绍了如何使用Java通过SMTP协议和Socket连接,结合DNS的MX记录查询,来验证用户输入的邮箱地址是否真实存在的过程。通过示例代码展示了如何实现这一功能。
摘要由CSDN通过智能技术生成

最近遇到一个需求:需要验证用户填写的邮箱地址是否真实存在,是否可达。和普通的正则表达式不同,他要求尝试链接目标邮箱服务器并请求校验目标邮箱是否存在。

先来了解

DNS之MX记录

对于DNS不了解的,请移步百度搜索。

DNS中除了A记录(域名-IP映射)之外,还有MX记录(邮件交换记录),CNAME记录(别名,咱不管)。

MX记录就是为了在发送邮件时使用友好域名规则,比如我们发送到QQ邮箱xxx@qq.com。我们填写地址是到“qq.com”,但实际上可能服务器地址千奇百怪/而且许有多个。在设置DNS时可以顺带设置MX记录。

说白了,“qq.com”只是域名,做HTTP请求响应地址,你邮件能发到Tomcat上吗?那我们发到“qq.com”上面的邮件哪里去了,我们把自己想象成一个邮件服务器,你的用户让你给xxx@qq.com发一封信,你如何操作?找mx记录是必要的。

SMTP之纯Socket访问

对于SMTP不了解或Java Socket不了解的,请移步百度搜索。

邮件协议是匿名协议,我们通过SMTP协议可以让邮件服务器来验证目标地址是否真实存在。

代码实现

由以上介绍可知:通过DNS中MX记录可以找到邮件服务器地址,通过SMTP协议可以让邮件服务器验证目标邮箱地址的真实性。

那么我们就来进行编码实现。

首先需要查询DNS,这个需要用到一个Java查询DNS的组件dnsjava(下载),自己写太麻烦。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 //查找mx记录

2 Record[] mxRecords = newLookup(host, Type.MX).run();3 if(ArrayUtils.isEmpty(mxRecords)) return false;4 //邮件服务器地址

5 String mxHost = ((MXRecord)mxRecords[0]).getTarget().toString();6 if(mxRecords.length > 1) { //优先级排序

7 List arrRecords = new ArrayList();8 Collections.addAll(arrRecords, mxRecords);9 Collections.sort(arrRecords, new Comparator() {10

11 public intcompare(Record o1, Record o2) {12 return newCompareToBuilder().append(((MXRecord)o1).getPriority(), ((MXRecord)o2).getPriority()).toComparison();13 }14

15 });16 mxHost = ((MXRecord)arrRecords.get(0)).getTarget().toString();17 }

mx

(上面代码中的生僻类型就是来自dnsjava,我使用apache-commons组件来判断空值和构建排序,return false是在查询失败时。)

接下来通过优先级排序(mx记录有这个属性)取第一个邮件服务器地址来链接。

这里的主要代码是通过SMTP发送RCPT TO指令来指定邮件接收方,如果这个地址存在则服务器返回成功状态,如果没有的话则返回错误指令。

1 importjava.io.BufferedInputStream;2 importjava.io.BufferedReader;3 importjava.io.BufferedWriter;4 importjava.io.IOException;5 importjava.io.InputStreamReader;6 importjava.io.OutputStreamWriter;7 importjava.net.InetSocketAddress;8 importjava.net.Socket;9 importjava.util.ArrayList;10 importjava.util.Collections;11 importjava.util.Comparator;12 importjava.util.List;13

14 importorg.apache.commons.lang.ArrayUtils;15 importorg.apache.commons.lang.StringUtils;16 importorg.apache.commons.lang.builder.CompareToBuilder;17 importorg.xbill.DNS.Lookup;18 importorg.xbill.DNS.MXRecord;19 importorg.xbill.DNS.Record;20 importorg.xbill.DNS.TextParseException;21 importorg.xbill.DNS.Type;22

23

24 public classMailValid {25

26 public static voidmain(String[] args) {27 System.out.println(new MailValid().valid("100582783@qq.com", "jootmir.org"));28 }29

30 /**

31 * 验证邮箱是否存在32 *
33 * 由于要读取IO,会造成线程阻塞34 *35 *@paramtoMail36 * 要验证的邮箱37 *@paramdomain38 * 发出验证请求的域名(是当前站点的域名,可以任意指定)39 *@return

40 * 邮箱是否可达41 */

42 public booleanvalid(String toMail, String domain) {43 if(StringUtils.isBlank(toMail) || StringUtils.isBlank(domain)) return false;44 if(!StringUtils.contains(toMail, '@')) return false;45 String host = toMail.substring(toMail.indexOf('@') + 1);46 if(host.equals(domain)) return false;47 Socket socket = newSocket();48 try{49 //查找mx记录

50 Record[] mxRecords = newLookup(host, Type.MX).run();51 if(ArrayUtils.isEmpty(mxRecords)) return false;52 //邮件服务器地址

53 String mxHost = ((MXRecord)mxRecords[0]).getTarget().toString();54 if(mxRecords.length > 1) { //优先级排序

55 List arrRecords = new ArrayList();56 Collections.addAll(arrRecords, mxRecords);57 Collections.sort(arrRecords, new Comparator() {58

59 public intcompare(Record o1, Record o2) {60 return newCompareToBuilder().append(((MXRecord)o1).getPriority(), ((MXRecord)o2).getPriority()).toComparison();61 }62

63 });64 mxHost = ((MXRecord)arrRecords.get(0)).getTarget().toString();65 }66 //开始smtp

67 socket.connect(new InetSocketAddress(mxHost, 25));68 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(newBufferedInputStream(socket.getInputStream())));69 BufferedWriter bufferedWriter = new BufferedWriter(newOutputStreamWriter(socket.getOutputStream()));70 //超时时间(毫秒)

71 long timeout = 6000;72 //睡眠时间片段(50毫秒)

73 int sleepSect = 50;74

75 //连接(服务器是否就绪)

76 if(getResponseCode(timeout, sleepSect, bufferedReader) != 220) {77 return false;78 }79

80 //握手

81 bufferedWriter.write("HELO " + domain + "\r\n");82 bufferedWriter.flush();83 if(getResponseCode(timeout, sleepSect, bufferedReader) != 250) {84 return false;85 }86 //身份

87 bufferedWriter.write("MAIL FROM: \r\n");88 bufferedWriter.flush();89 if(getResponseCode(timeout, sleepSect, bufferedReader) != 250) {90 return false;91 }92 //验证

93 bufferedWriter.write("RCPT TO: \r\n");94 bufferedWriter.flush();95 if(getResponseCode(timeout, sleepSect, bufferedReader) != 250) {96 return false;97 }98 //断开

99 bufferedWriter.write("QUIT\r\n");100 bufferedWriter.flush();101 return true;102 } catch(NumberFormatException e) {103 } catch(TextParseException e) {104 } catch(IOException e) {105 } catch(InterruptedException e) {106 } finally{107 try{108 socket.close();109 } catch(IOException e) {110 }111 }112 return false;113 }114

115 private int getResponseCode(long timeout, int sleepSect, BufferedReader bufferedReader) throwsInterruptedException, NumberFormatException, IOException {116 int code = 0;117 for(long i = sleepSect; i < timeout; i +=sleepSect) {118 Thread.sleep(sleepSect);119 if(bufferedReader.ready()) {120 String outline =bufferedReader.readLine();121 //FIXME 读完……

122 while(bufferedReader.ready())123 /*System.out.println(*/bufferedReader.readLine()/*)*/;124 /*System.out.println(outline);*/

125 code = Integer.parseInt(outline.substring(0, 3));126 break;127 }128 }129 returncode;130 }131 }

(解锁和输出123、124行数据可以让你更加清晰SMTP协议)

对于企业邮箱,可能无法正常验证,这个是因为服务器问题。另外,dnsjava查询DNS是有缓存的。

现在工作越来越紧张,对于技术的理解也较以前深刻。现在写出的代码可能较为精简(这意味着如果你是新手可能不容易理解)。

联系我,一起交流

欢迎您移步我们的交流群,无聊的时候大家一起打发时间:a0f609b288c7de88131b6f6ba37c81b3.png

或者通过QQ与我联系:d4e784ff4b6a12048cd256a11d33658c.png

(最后编辑时间2015-04-29 10:27:44)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值