.NET SmtpClient:是否有一种方法可以确保在发送MailMessage之前解析所有电子邮件?

6
我正在使用SmtpClient发送电子邮件给多个收件人。当员工离开公司后,他们的电子邮件地址变得无效。由于他们的电子邮件地址在手动删除之前仍然保留在我们的数据库中,因此尝试向他们发送电子邮件会导致我们的应用程序在 SmtpClient.Send(MailMessage)期间抛出异常。然而,尽管抛出了异常,它仍然发送电子邮件。这是一个问题,因为我们希望通过阻止用户尝试保存记录并显示友好的消息来处理此错误,建议从数据库中删除任何无效的关联。
如果有一种方法可以迭代所有收件人以确保它们都有效,我们就可以保持所有电子邮件不被发送,直到用户满足一组条件。

1
取决于您需要多彻底 - 您可能需要查看第三方组件,例如EmailVerify.NET - Bridge
您提到这些是员工。您是否使用Exchange Server进行电子邮件或Active Directory进行身份验证?所有要检查的电子邮件都是员工的吗?一种选择是在发送之前遍历地址并检查AD中的帐户状态或通过EWS进行验证。 - randcd
2个回答

7

这是一个很久的问题,我不知道你是否已经解决了它。

根据MSDN:http://msdn.microsoft.com/en-us/library/swas0fwc(v=vs.100).aspx

当使用Send发送电子邮件到多个收件人并且SMTP服务器接受某些收件人而拒绝其他收件人时,Send将向已接受的收件人发送电子邮件,然后会抛出SmtpFailedRecipientsException。异常将包含被拒绝的收件人列表。

以下是从MSDN中截取的捕获此异常的示例:

try {
    client.Send(message);
}
catch (SmtpFailedRecipientsException ex) {
    for (int i = 0; i < ex.InnerExceptions.Length; i++) {
        SmtpStatusCode status = ex.InnerExceptions[i].StatusCode;
        if (status == SmtpStatusCode.MailboxBusy || status == SmtpStatusCode.MailboxUnavailable) {
            Console.WriteLine("Delivery failed - retrying in 5 seconds.");
            System.Threading.Thread.Sleep(5000);
            client.Send(message);
        } 
        else {
            Console.WriteLine("Failed to deliver message to {0}", ex.InnerExceptions[i].FailedRecipient);
        }
    }
}

完整的示例请参见:http://msdn.microsoft.com/en-us/library/system.net.mail.smtpfailedrecipientsexception.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2

Send 内部使用从 RCPT TO 命令返回的 statuscode 来引发相应的异常。

smtpTransport.SendMailRecipientCommand.Send 方法中检查 PrepareCommand 的实现(此方法由 SmtpClient.Send 在内部调用)。它使用 RCPT TO 获取 StatusCode,然后在 CheckResponse 方法中解析,相应地引发 SmtpFailedRecipientsException 异常。但是,VRFY 和 RCPT 都不是非常可靠,因为邮件服务器倾向于延迟(限制 NDR)或将响应吞噬作为反垃圾邮件措施。


1
我在这里遇到了困难。突然间,异常不再被抛出。当我最初撰写这个问题时,异常是被抛出的,但现在Exchange Server只是发送一封电子邮件说明无法将邮件发送给特定的收件人。你知道可能发生了什么变化吗? - oscilatingcretin
1
@oscilatingcretin 我刚刚在我的服务器上测试了它,它完全正常。我能够捕获 SmtpFailedRecipientsException。请检查您的Exchange环境是否更改了收件人过滤设置。有两个设置需要查看:(1) SMTP Tarpitting: Tarpitting会延迟“5.1.1 User Unknown”响应。可能是tarpitting导致您代码中的send超时。(2) Recipient Filtering: 如果将RecipientValidationEnabled设置为false,则服务器将响应“2.1.5 Recipient OK”,但仍会生成NDR。异常未被引发。 - Abhitalks
如果您只想检查收件人的存在以立即阻止用户,则可能需要首先针对AD进行检查。如果用户在AD中可用,则只需继续执行邮件代码。UserPrincipal.FindByIdentity将是您的好帮手。 - Abhitalks

2
请看以下内容:如何在不发送电子邮件的情况下检查电子邮件地址是否存在? 您想要做的是在继续发送之前检查电子邮件是否存在。
因此,正如链接答案中所述,尝试查看公司邮件服务器是否支持VRFYRCPT
引用:

您可以连接到服务器并发出VRFY命令。很少有服务器支持此命令,但它就是为此而设计的。如果服务器以2.0.0 DSN响应,则用户存在。

VRFY user

您可以发出RCPT,并查看邮件是否被拒绝。

MAIL FROM:<>

RCPT TO:


+1 我以前从未尝试过,但它看起来非常有趣! - pedrommuller
这正是SmtpClient.Send在内部执行的操作。请检查smtpTransport.SendMail方法中RecipientCommand.Send方法中PrepareCommand的实现(该方法由SmtpClient.Send在内部调用)。它使用RCPT TO获取StatusCode,然后在CheckResponse方法中解析,并相应地引发SmtpFailedRecipientsException异常。然而,VRFY和RCPT都不是非常可靠,因为邮件服务器往往会延迟(节流NDR)或吞掉响应作为反垃圾邮件措施。 - Abhitalks
谢谢@abhitalks,那么有什么可靠的解决方案吗?或者至少有一个变通方法吗?有什么想法吗? - pedrommuller
遗憾的是没有。最接近的方法是在“Send”中捕获异常。我们无法强制任何邮件服务器立即响应(甚至响应)。反垃圾邮件措施是必要的不便 :) - Abhitalks
@abhitalks,抱歉,我还是不明白。我会开一个新的问题。 - Arturo Torres Sánchez
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接