我需要发送数百封新闻通讯,但想首先检查服务器上是否存在电子邮件。它被称为 邮件传输协议 验证,至少我是这样认为的,基于我对互联网的研究。

有几个库可以做到这一点,还有一个包含开源代码的页面 ASP经典版 (http://www.coveryourasp.com/ValidateEmail.asp#Result3),但是我很难阅读ASP Classic,而且它似乎使用了一些第三方库......

是否有一些 C# 中的 SMTP 验证代码,和/或对其工作原理的一般解释?

有帮助吗?

解决方案

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

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

其他提示

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

虽然许多域确实会因滥用而返回误报,但仍然有一些出色的组件可以执行除 SMTP 验证之外的多个级别的验证。例如,值得首先检查一下该域是否存在。我正在编制与此问题相关的资源列表,您可以在此处跟踪:

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

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

为了获得防弹表单和良好的用户体验,验证电子邮件地址的尽可能多的方面很有帮助。我可以从 ASPNetMX 他们检查的验证器:

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

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

当然,在注册屏幕或表单中使用此类服务​​的最佳实践是将此类验证与验证过程结合起来,以确保电子邮件地址有效。在验证过程之前使用电子邮件验证器的好处在于,它将带来更好的整体用户体验。

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

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;
    }
}

谢谢,向拉胡尔·萨拉斯瓦特(Rahul Saraswat)

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

不要误解这一点,但如今向不止少数人发送新闻通讯是一件相当严重的事情。是的,您需要监控退回邮件(被拒绝的电子邮件),这可能在 SMTP 发送期间同步发生(通常如果您连接到的 SMTP 服务器是权威服务器),或者作为系统生成的电子邮件消息异步发生,在发送后一段时间发生SMTP发送成功。

发送这些电子邮件时还要牢记《反垃圾邮件法》并遵守法律;您必须提供一个取消订阅链接以及一个实际街道地址(以识别您的身份,并允许用户通过蜗牛邮件发送取消订阅请求(如果他们愿意)。

如果不做这些事情,最好的情况是您的 IP 会被空路由,最坏的情况可能会被起诉。

你可能需要这个 .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);
   }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top