电子邮件SMTP验证器

时间:2008-08-26 06:10:01

标签: validation email

我需要发送数百份简报,但想先查看服务器上是否有电子邮件。根据我对互联网的研究,它被称为SMTP验证,至少我是这么认为的。

有几个库可以做到这一点,还有一个包含ASP Classichttp://www.coveryourasp.com/ValidateEmail.asp#Result3)中的开源代码的页面,但我很难阅读ASP Classic,它似乎使用了一些第三方图书馆......

是否有一些用于C#中SMTP验证的代码,和/或其工作原理的一般说明?

7 个答案:

答案 0 :(得分:18)

请注意,出于垃圾邮件保护原因,大多数MTA(邮件传输代理)都会关闭VRFY命令,如果您连续尝试多个RCPT TO,它们甚至可能会阻止您(请参阅http://www.spamresource.com/2007/01/whatever-happened-to-vrfy.html)。因此,即使您找到一个库来进行验证,也不会有太多价值。 Ishmaeel是对的,真正找到答案的唯一方法是发送电子邮件,看看它是否会反弹。

@Hrvoje:是的,我建议您监控被拒绝的电子邮件。但是:并非所有退回的邮件都会自动结束您的“不存在”列表,您还必须区分临时(例如邮箱已满)和永久性错误。

答案 1 :(得分:10)

SMTP是通过TCP / IP承载的基于文本的协议。

您的验证程序需要打开到服务器端口25(SMTP)的TCP / IP连接,写几行并阅读答案。验证在“RCTP TO”行和“VFRY”行上完成(但并非总是如此)。

SMTP RFC描述了它的工作原理(参见下面的Green@Beta.ARPA,S是客户端发送的行,R是从服务器接收的行):

Example of the SMTP Procedure

         This SMTP example shows mail sent by Smith at host Alpha.ARPA,
         to Jones, Green, and Brown at host Beta.ARPA.  Here we assume
         that host Alpha contacts host Beta directly.

            S: MAIL FROM:
            R: 250 OK

            S: RCPT TO:
            R: 250 OK

            S: RCPT TO:
            R: 550 No such user here

答案 2 :(得分:4)

虽然很多域都会因滥用而返回误报,但仍有一些很棒的组件可以执行多个级别的验证,而不仅仅是SMTP验证。例如,首先检查是否至少存在域是值得的。我正在编译我自己的与此问题相关的资源列表,您可以在此处跟踪:

http://delicious.com/dworthley/email.validation

对于那些可能想要添加到此列表中的人,我还将包括我目前所拥有的内容:

对于防弹表单和出色的用户体验,尽可能多地验证电子邮件地址是有帮助的。我可以从aspNetMX验证器看到他们检查:

  • 语法
  • 针对不良电子邮件地址列表的电子邮件
  • 针对坏域列表的域
  • 邮箱域列表
  • 域名是否存在
  • 域名是否有MX记录
  • 最后通过SMTP无论邮箱是否存在

管理员可以通过返回基本上所有帐户验证请求的真实情况来规避这最后一步,但在大多数情况下,如果用户故意输入了错误的地址,那么它已被捕获。如果它是地址的域部分中的用户错误,那么也会被捕获。

当然,将此类服务用于注册屏幕或表单的最佳做法是将此类验证与验证过程相结合,以确保电子邮件地址有效。在验证过程中使用电子邮件验证程序的好处是它可以提供更好的整体用户体验。

答案 3 :(得分:3)

您可以尝试以下代码,它对我来说很好:

public class EmailTest {
    private static int hear(BufferedReader in) throws IOException {
        String line = null;
        int res = 0;

        while ((line = in.readLine()) != null) {
            String pfx = line.substring(0, 3);
            try {
                res = Integer.parseInt(pfx);
            } catch (Exception ex) {
                res = -1;
            }
            if (line.charAt(3) != '-')
                break;
        }

        return res;
    }

    private static void say(BufferedWriter wr, String text) throws IOException {
        wr.write(text + "\r\n");
        wr.flush();

        return;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static ArrayList getMX(String hostName) throws NamingException {
        // Perform a DNS lookup for MX records in the domain
        Hashtable env = new Hashtable();
        env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
        DirContext ictx = new InitialDirContext(env);
        Attributes attrs = ictx.getAttributes(hostName, new String[] { "MX" });
        Attribute attr = attrs.get("MX");

        // if we don't have an MX record, try the machine itself
        if ((attr == null) || (attr.size() == 0)) {
            attrs = ictx.getAttributes(hostName, new String[] { "A" });
            attr = attrs.get("A");
            if (attr == null)
                throw new NamingException("No match for name '" + hostName + "'");
        }
        /*
         Huzzah! we have machines to try. Return them as an array list
         NOTE: We SHOULD take the preference into account to be absolutely
         correct. This is left as an exercise for anyone who cares.
         */
        ArrayList res = new ArrayList();
        NamingEnumeration en = attr.getAll();

        while (en.hasMore()) {
            String mailhost;
            String x = (String) en.next();
            String f[] = x.split(" ");
            // THE fix *************
            if (f.length == 1)
                mailhost = f[0];
            else if (f[1].endsWith("."))
                mailhost = f[1].substring(0, (f[1].length() - 1));
            else
                mailhost = f[1];
            // THE fix *************
            res.add(mailhost);
        }
        return res;
    }

    @SuppressWarnings("rawtypes")
    public static boolean isAddressValid(String address) {
        // Find the separator for the domain name
        int pos = address.indexOf('@');

        // If the address does not contain an '@', it's not valid
        if (pos == -1)
            return false;

        // Isolate the domain/machine name and get a list of mail exchangers
        String domain = address.substring(++pos);
        ArrayList mxList = null;
        try {
            mxList = getMX(domain);
        } catch (NamingException ex) {
            return false;
        }

        /*
        Just because we can send mail to the domain, doesn't mean that the
        address is valid, but if we can't, it's a sure sign that it isn't
        */
        if (mxList.size() == 0)
            return false;

        /* 
        Now, do the SMTP validation, try each mail exchanger until we get
        a positive acceptance. It *MAY* be possible for one MX to allow
        a message [store and forwarder for example] and another [like
        the actual mail server] to reject it. This is why we REALLY ought
        to take the preference into account.
        */
        for (int mx = 0; mx < mxList.size(); mx++) {
            boolean valid = false;
            try {
                int res;
                //
                Socket skt = new Socket((String) mxList.get(mx), 25);
                BufferedReader rdr = new BufferedReader(new InputStreamReader(skt.getInputStream()));
                BufferedWriter wtr = new BufferedWriter(new OutputStreamWriter(skt.getOutputStream()));

                res = hear(rdr);
                if (res != 220)
                    throw new Exception("Invalid header");
                say(wtr, "EHLO rgagnon.com");

                res = hear(rdr);
                if (res != 250)
                    throw new Exception("Not ESMTP");

                // validate the sender address
                say(wtr, "MAIL FROM: <tim@orbaker.com>");
                res = hear(rdr);
                if (res != 250)
                    throw new Exception("Sender rejected");

                say(wtr, "RCPT TO: <" + address + ">");
                res = hear(rdr);

                // be polite
                say(wtr, "RSET");
                hear(rdr);
                say(wtr, "QUIT");
                hear(rdr);
                if (res != 250)
                    throw new Exception("Address is not valid!");

                valid = true;
                rdr.close();
                wtr.close();
                skt.close();
            } catch (Exception ex) {
                // Do nothing but try next host
                ex.printStackTrace();
            } finally {
                if (valid)
                    return true;
            }
        }
        return false;
    }

    public static void main(String args[]) {
        String testData[] = { "rahul.saraswat@techblue.com", "rahul.saraswat@techblue.co.uk", "srswt.rahul12345@gmail.com",
        "srswt.rahul@gmail.com" };
        System.out.println(testData.length);
        for (int ctr = 0; ctr < testData.length; ctr++) {
            System.out.println(testData[ctr] + " is valid? " + isAddressValid(testData[ctr]));
        }
        return;
    }
}

谢谢&amp;问候 Rahul Saraswat

答案 4 :(得分:2)

Real(TM)电子邮件验证正在尝试向该地址发送内容,并查看它是否被拒绝/退回。因此,您只需将它们发送出去,并从邮件列表中删除失败的地址。

答案 5 :(得分:2)

不要采取错误的方式,但这些天向少数人发送简讯是一件相当严重的事情。是的,您需要监控在SMTP发送过程中可能同步发生的退回(拒绝的电子邮件)(通常,如果您连接的SMTP服务器是权威的),或者是系统生成的电子邮件消息,这些消息会在一段时间后发生SMTP发送成功。

在发送这些电子邮件时,请牢记“反垃圾邮件法”并遵守法律规定;你必须提供一个unsub链接以及一个物理街道地址(以识别你和t0允许用户通过蜗牛邮件发送unsub请求,如果他们愿意的话)。

如果不做这些事情,可能会使您的IP无效,并在最坏情况下起诉。

答案 6 :(得分:1)

您可能需要Email Validator component for .NET

以下是代码示例:


   // Create a new instance of the EmailValidator class.
   EmailValidator em = new EmailValidator();
   em.MessageLogging += em_MessageLogging;
   em.EmailValidated += em_EmailValidationCompleted;
   try
   {
       string[] list = new string[3] { "test1@testdomain.com", "test2@testdomain.com", "test3@testdomain.com" };
       em.ValidateEmails(list);
   }
   catch (EmailValidatorException exc2)
   {
       Console.WriteLine("EmailValidatorException: " + exc2.Message);
   }