.NET 使用 SmtpClient 和 Mandrill SMTP 发送失败

Posted

技术标签:

【中文标题】.NET 使用 SmtpClient 和 Mandrill SMTP 发送失败【英文标题】:.NET sending using SmtpClient with Mandrill SMTP fails 【发布时间】:2017-10-19 17:40:31 【问题描述】:

当以下代码中的 mailFromName 包含“æ”、“ø”或“å”时,我们正面临通过 Mandrill SMTP 发送邮件静默失败的难题。当我们使用另一个 SMTP 时,邮件发送得非常好。

Mail.ReplyToList.Add(New MailAddress(mailFromAddress, mailFromName, System.Text.Encoding.UTF8))

我们使用 .NET smtpClient 类。

Dim SmtpClient As New System.Net.Mail.SmtpClient
SmtpClient.Send(Mail)
SmtpClient.Dispose()

更新

正如 cmets 中所建议的,我同意这看起来像是一个编码问题,但在我们这边看不到我能做些什么。

它似乎只连接到包含 æ、ø 和 å 的 RepleyToList 而不是 Mail.To,我以类似的方式定义如下:

Dim mTo As New MailAddress(mailToAddress, mailToName, System.Text.Encoding.UTF8)
Mail.To.Add(mTo)

mailToName 可以包含 æ、ø 和 å 并且发送完全没问题。

很难证明某事没有发生,但我确定邮件没有发送,并且我确定它与replyToList 中的发件人名称相关联。

我怎么知道?

我在发送之前记录邮件。包含相关字符的邮件会被记录,但在 https://mandrillapp.com/activity 中永远不会显示,并且永远不会到达收件人。我删除了 æ、ø 或 å - 在 Mandrill 概述中都可以看到并且一切正常。

想看我的完整代码吗?

在这里,注意发送失败的邮件不会产生异常。

  Public Sub sendMail(ByVal mailFromAddress As String, ByVal mailFromName As String, _
                      ByVal mailToAddress As String, ByVal mailToName As String, ByVal mailCcAddress As String, ByVal mailBCcAddress As String, _
                      ByVal mailPriority As Net.Mail.MailPriority, ByVal IsBodyhtml As Boolean, ByVal mailSubject As String, _
                      ByVal bodyPlain As String, ByVal bodyHTML As String)
    Const maxtry As Integer = 3
    Dim tries As Integer = 0
    Dim failed As Boolean = False

    ' mailFromName = mailFromName.Replace("æ", "ae")

    Do
      tries += 1

      Try

        failed = False
        Dim Mail As New MailMessage


        If mailFromAddress <> String.Empty Then
          'Mail.ReplyTo = New MailAddress(mailFromAddress, mailFromName, System.Text.Encoding.UTF8)
          Mail.ReplyToList.Add(New MailAddress(mailFromAddress, mailFromName, System.Text.Encoding.UTF8))
        Else
          'Mail.ReplyTo = New MailAddress(Me.MailAddressFrom, Me.MailAddressDisplayName, System.Text.Encoding.UTF8)
          Mail.ReplyToList.Add(New MailAddress(Me.MailAddressFrom, Me.MailAddressDisplayName, System.Text.Encoding.UTF8))
        End If
        Mail.From = New MailAddress(Me.MailAddressFrom, Me.MailAddressDisplayName, System.Text.Encoding.UTF8)
        Mail.Sender = New MailAddress(Me.MailAddressFrom, Me.MailAddressDisplayName, System.Text.Encoding.UTF8)

        If mailToAddress <> String.Empty Then
          Dim mTo As New MailAddress(mailToAddress, mailToName, System.Text.Encoding.UTF8) 'UTF8
          Mail.To.Add(mTo)
        End If
        If mailCcAddress <> String.Empty Then
          Dim mCc As New MailAddress(mailCcAddress)
          Mail.CC.Add(mCc)
        End If
        If mailBCcAddress <> String.Empty Then
          Dim mBCc As New MailAddress(mailBCcAddress)
          Mail.Bcc.Add(mBCc)
        End If

        Mail.Priority = mailPriority

        Mail.DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure

        Mail.IsBodyHtml = IsBodyHtml 
        Mail.HeadersEncoding = Encoding.GetEncoding("utf-8")

        Mail.Subject = mailSubject
        Mail.SubjectEncoding = Encoding.GetEncoding("utf-8") ' = System.Text.Encoding.Default 'UTF8 'Default ' Test on all possible encodings

        If IsBodyHtml Then
          Mail.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(bodyHTML, System.Text.Encoding.Default, "text/html"))
        End If
        Mail.BodyEncoding = Encoding.GetEncoding("utf-8")
        Mail.Body = bodyPlain

        ' Add to log
        addToMailLog(mailToAddress, mailCcAddress, mailSubject, bodyPlain)

        ' Send
        Dim SmtpClient As New System.Net.Mail.SmtpClient
        'SmtpClient.ServicePoint.MaxIdleTime = 1
        SmtpClient.Send(Mail)
        Me._status = EMailStatus.EOkay
        SmtpClient.Dispose()

      Catch ex As Exception
        Dim debugInfo As New CDebug("sendMail", "Try: " & tries.ToString & ", UserId: " & Me.UserId, ex.ToString, Me.UserId, String.Empty)
        Me._status = EMailStatus.EMailSendError
        failed = True
      End Try

    Loop Until (failed = False Or tries >= maxtry)

  End Sub

更新二

我现在已经使用 WireShark 跟踪了 SMTP 通信。请参阅屏幕截图,该屏幕截图显示了未传递且未显示在 Mandrill 活动列表中的邮件的通信 - 即使我们得到 SMTP 响应正常和排队 ID。

我举了三个例子:

已交付:

mailFromName = "xxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxxxx"

未送达:

mailFromName = "xxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxæxx"

已交付:

mailFromName = "æxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxxxx"

【问题讨论】:

似乎很明显这是一个编码问题。至少通过this Q+A 工作。如果这没有帮助,请具体说明您如何知道地址被拒绝。 感谢您的评论,我查看了您的链接,但与我们的问题没有真正的联系 - 请参阅我更新的问题了解更多详细信息。 SmtpClient 上有一个名为 DeliveryFormat 的设置。如果将其设置为“国际”会发生什么? SmtpClient.DeliveryFormat = SmtpDeliveryFormat.International 谢谢 - 不幸的是 DeliveryFormat 是在 .NET 4.5 框架中引入的,而我们使用 4.0 您至少可以使用 .NET 4.5 进行测试吗?据我所知,以前版本中的 SmtpClient 并不支持所有国际字符的情况。如果您在 .NET 4.5 中仍然遇到此问题,我们至少可以排除一个潜在原因。 【参考方案1】:

我相信我已经找到了对此的解释。似乎 smtpclient 在主题和回复显示名称的大约 72 个字符之后添加了一个新行。问题是这似乎发生在字符串被编码之后。因此,在某些情况下,在编码字符的中间添加了一个换行符,这 afaik 是非法的。

我不知道为什么 Mandrill SMTP 服务器失败但没有返回错误,而其他 SMTP 服务器处理得很好。

现在我了解了正在发生的事情,我必须想办法解决它 - 最好的建议会得到赏金。

【讨论】:

您实施过解决方案吗?我相信我遇到了这个问题 没有,从未找到解决方案 - 最终使用了对我们来说足够的西方编码 谢谢,最后我们转向了 MailKit

以上是关于.NET 使用 SmtpClient 和 Mandrill SMTP 发送失败的主要内容,如果未能解决你的问题,请参考以下文章

将“SmtpClient.EnableSsl”设置为 true 时,“System.Net.Mail.SmtpClient”需要哪些端口?

使用 SmtpClient 和 MailMessage 时如何禁止电子邮件验证

如何使用 POP3 和 SmtpClient 转发多部分 MIME 电子邮件?

.NET SmtpClient 在使用密件抄送时暴露 10 个电子邮件地址(通过 Mandrill)

SmtpClient.SendAsync 阻止我的 ASP.NET MVC 请求

是否可以捕获使用 SmtpClient 发送的电子邮件的“消息 ID”?