.NET 使用 SmtpClient 和 Mandrill SMTP 发送失败
.NET sending using SmtpClient with Mandrill SMTP fails
当以下代码中的 mailFromName 包含“æ”、“ø”或“å”时,通过 Mandrill SMTP 发送邮件静默失败时,我们遇到了一个难题。当我们使用另一个 SMTP 时,邮件发送得很好。
Mail.ReplyToList.Add(New MailAddress(mailFromAddress, mailFromName, System.Text.Encoding.UTF8))
我们使用 .NET smtpClient class。
Dim SmtpClient As New System.Net.Mail.SmtpClient
SmtpClient.Send(Mail)
SmtpClient.Dispose()
更新
正如评论中所建议的那样,我同意这看起来像是一个编码问题,但我看不出我能对此做些什么。
它似乎只连接到包含 æ、ø 和 å 的 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 Overview 中都可见,一切正常。
想看我的完整代码吗?
在这里,注意发送失败的邮件不会产生异常。
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 activity 列表中的邮件通信的屏幕截图 - 即使我们收到 SMTP 响应正常且已排队 ID。
我举三个例子:
已交付:
mailFromName = "xxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxxxx"
未交付:
mailFromName = "xxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxæxx"
已交付:
mailFromName = "æxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxxxx"
我相信我已经找到了对此的解释。似乎 smtpclient 在主题和回复显示名称的大约 72 个字符之后添加了一个新行。问题是这似乎发生在字符串被编码之后。因此,在某些情况下,在编码字符的中间添加换行符,这在我看来是非法的。
我不确定为什么 Mandrill SMTP 服务器失败而没有返回错误,而其他 SMTP 服务器可以很好地处理这种情况。
现在我明白发生了什么,我必须想办法解决它 - 最好的建议会得到赏金。
当以下代码中的 mailFromName 包含“æ”、“ø”或“å”时,通过 Mandrill SMTP 发送邮件静默失败时,我们遇到了一个难题。当我们使用另一个 SMTP 时,邮件发送得很好。
Mail.ReplyToList.Add(New MailAddress(mailFromAddress, mailFromName, System.Text.Encoding.UTF8))
我们使用 .NET smtpClient class。
Dim SmtpClient As New System.Net.Mail.SmtpClient
SmtpClient.Send(Mail)
SmtpClient.Dispose()
更新
正如评论中所建议的那样,我同意这看起来像是一个编码问题,但我看不出我能对此做些什么。
它似乎只连接到包含 æ、ø 和 å 的 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 Overview 中都可见,一切正常。
想看我的完整代码吗?
在这里,注意发送失败的邮件不会产生异常。
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 activity 列表中的邮件通信的屏幕截图 - 即使我们收到 SMTP 响应正常且已排队 ID。
我举三个例子:
已交付:
mailFromName = "xxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxxxx"
未交付:
mailFromName = "xxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxæxx"
已交付:
mailFromName = "æxx xxxxxxxxx xxxx - xxxxxxxxxx xxxxxxx xxxxxxxxx"
我相信我已经找到了对此的解释。似乎 smtpclient 在主题和回复显示名称的大约 72 个字符之后添加了一个新行。问题是这似乎发生在字符串被编码之后。因此,在某些情况下,在编码字符的中间添加换行符,这在我看来是非法的。
我不确定为什么 Mandrill SMTP 服务器失败而没有返回错误,而其他 SMTP 服务器可以很好地处理这种情况。
现在我明白发生了什么,我必须想办法解决它 - 最好的建议会得到赏金。