DNS参照するメールアドレスチェック

正規表現だけでメールアドレスチェックをして良しとするのは
あまり良くない。
メールアドレスが指すドメインだけでも、DNSサーバに問い合わせたい。
Java の場合、
以下を参考に、DNS lookUp で検証する。
https://docs.oracle.com/javase/jp/6/technotes/guides/jndi/jndi-dns.html

Java/JNDIのDNSサービスプロバイダによる名前解決 - Glamenv-Septzen.net

import java.util.Hashtable;
import java.util.regex.Pattern;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
/**
 * メールバリデーションチェック
 * @param mail メールアドレス文字列
 * @return true=存在しないメールアドレス
 */
public static boolean validateMailAdress(String mail) {
    Pattern ptn = Pattern.compile("^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,3}){1}$");
    if (ptn.matcher(mail).matches()){
        Hashtable<String, String> env = new Hashtable<>();
        env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
        try{
            DirContext ictx = new InitialDirContext(env);
            Attributes attrs = ictx.getAttributes(mail.split("@")[1], new String[]{"MX"});
            Attribute attr = attrs.get("MX");
            if (attr==null){
                return true;
            }
            return attr.size() < 1;
        }catch(NamingException e){
            return true;
        }
    }
    return true;
}

正規表現チェックと組み合わせて問い合わせを行っている。

interface にした方がいいかな。。。

import java.util.Hashtable;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.function.Function;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public interface MailValidation{
    Pattern ptn = Pattern.compile("^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,3}){1}$");
    
    public static Function<String, Boolean> of(){
        return s -> validate(s);
    }
    
    static boolean validate(String mail) {
        Objects.requireNonNull(mail);
        if (ptn.matcher(mail).matches()){
            Hashtable<String, String> env = new Hashtable<>();
            env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
            try{
                DirContext ictx = new InitialDirContext(env);
                Attributes attrs = ictx.getAttributes(mail.split("@")[1], new String[]{"MX"});
                Attribute attr = attrs.get("MX");
                if (attr==null){
                    return true;
                }
                return attr.size() < 1;
            }catch(NamingException e){
                return true;
            }
        }
        return true;
    }
}

Python の場合、
dnspython を使う方法(他のパッケージを使う方法もあると思うが)
以下を参考に、、、
www.tutorialspoint.com

 pip install dnspython

バージョンにより差がある。
dnspython version 2.6.1 では、lookup の問い合わせ query は、
 DeprecationWarning: please use dns.resolver.resolve() instead
の警告が出るので、dns.resolver.resolve() を使用する。

import dns.resolver
from dns.resolver import NXDOMAIN

try:
    res = dns.resolver.resolve("gmail.com","MX")
    for ipval in res:
        print('IP', ipval.to_text())
except NXDOMAIN as e:
    print(e)

結果

alt4.gmail-smtp-in.l.google.com.
gmail-smtp-in.l.google.com.
alt3.gmail-smtp-in.l.google.com.
alt2.gmail-smtp-in.l.google.com.
alt1.gmail-smtp-in.l.google.com.

email_validator と組み合わせて、

from email_validator import validate_email, EmailNotValidError,  EmailUndeliverableError
import dns.resolver
from dns.resolver import NXDOMAIN
import sys

def validateMail(mail:str)->bool:
    try:
        validate_email(mail)
        dns.resolver.resolve(mail.split('@')[1], "MX")
        return False
    except NXDOMAIN as e:
        print(e, file=sys.stderr)
        return True
    except EmailUndeliverableError as e:
        print(e, file=sys.stderr)
        return True
    except EmailNotValidError as e:
        print(e, file=sys.stderr)
        return True