【问题标题】:Adding one recipient to MailMessage but add header to email clients see all recipients将一个收件人添加到 MailMessage 但将标头添加到电子邮件客户端查看所有收件人
【发布时间】:2013-10-31 18:48:40
【问题描述】:

我目前正在开发一个 C# 项目,我正在创建自己的 SMTP 服务器。它的工作量更少,但我正在努力让它工作,我可以向不同域上的多个收件人发送电子邮件。

我最初是这样做的,所以我会创建一个 MailMesssage 对象并运行以下命令来添加每个收件人

MailMessage message = new MailMessage();
message.To.add("someone@domain1.com");
message.To.add("someone@domain2.com");

如果不同的域通过谷歌应用服务器,我会得到 MX 记录 ALT2.ASPMX.L.GOOGLE.COM。当发送邮件时,虽然在上面添加了收件人,但谷歌会发回一个错误,因为他们不允许通过一个 SMTP 会话进行跨域发送。

因此我对其进行了重新设计,以便为每个收件人发送单独的电子邮件,我获得每个域的 MX 记录,因此我最终也得到了不同的 SMTP 会话。所以我收到的每个收件人只有一个message.To.add。我想要做的是添加一个标题,这样它仍然显示电子邮件收件人仍然会去someone@domain1.comsomeone@domain2.com

因此,就 MailMessage 组件而言,只有一个收件人,但标头显示多个收件人,因此当收到的邮件查看其客户端中的电子邮件时,它会显示该电子邮件发送至的所有收件人。

以下是我必须发送电子邮件的代码。

MXLookup mxLookup = new MXLookup();
                    List<string> recipients = addRecipientsToEmail(message.emailRecipients);
                    foreach (string recipient in recipients)
                    {
                        string domain = Classes.CommonTasks.getDomainFromEmail(recipient);
                        string[] mxRecords = mxLookup.getMXRecords(Classes.CommonTasks.getDomainFromEmail(domain));
                        if (mxRecords != null)
                        {
                            MailMessage composedMail = new MailMessage();
                            composedMail.From = new MailAddress(message.EmailFromAddress);
                            composedMail.To.Add(recipient);
                            composedMail.Subject = message.subject;
                            composedMail.Body = message.EmailBody;
                            composedMail.Headers.Add(getHeaders(recipients));

                            if (message.contentType.ToString().Contains("text/html"))
                            {
                                composedMail.IsBodyHtml = true;
                            }

                            SmtpClient smtp = new SmtpClient(mxRecords[0]);
                            smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
                            smtp.Port = 25;
                            if (Configuration.emailConfig.useSmtpMaxIdleTime)
                            {
                                smtp.ServicePoint.MaxIdleTime = 1;
                            }
                            library.logging(methodInfo, string.Format("Sending email via MX Record: {0}", mxRecords[0]));
                            smtp.Send(composedMail);
                            updateEmailStatus(message.emailID, EmailStatus.Sent);
                            library.logging(methodInfo, string.Format("Successfully sent email ID: {0}", message.emailID));

                        }

                        else
                        {
                            string error = string.Format("No MX Record found for domain: {0}", domain);
                            library.logging(methodInfo, error);
                            library.setAlarm(error, CommonTasks.AlarmStatus.Warning, methodInfo);
                        }

下面是我的 getHeaders 函数。

private NameValueCollection getHeaders(List<string> emailRecipients)
{
    string headers = "";
    NameValueCollection headersArray = new NameValueCollection();
    foreach (string recipient in emailRecipients)
    {
        headers += string.Format("{0}, ", recipient);
    }
    headersArray.Add("To", headers);
    return headersArray;
}

感谢您提供的任何帮助。

【问题讨论】:

  • 如果您实际上是在编写自己的 smtp server,为什么要通过 google 发送?修辞。无论如何,你有两个选择。选择 1:遵循 google.com 的指南并为每个人发送 1 条消息。我敢肯定,他们已经花费了相当多的时间来确保人们不会绕过他们的限制。选择 2:更改电子邮件提供商,或简单地设置您自己的邮件服务器。
  • 我正在通过 MX 记录发送收件人域,如我的问题中所述。我只是碰巧使用的是谷歌应用电子邮件域,因此电子邮件正在通过 Google MX 记录中继

标签: c# email smtp


【解决方案1】:

Boardy,首先,让我说,我理解您为什么使用自己的 SMTP 服务器而不是中继。我们正在做同样的事情,因为我们需要实时处理电子邮件故障,而不必依赖死信或 NDR。这只有在你控制传输通道的情况下才实用。

您在这里遇到的问题是无法将 RCPT TO 命令和“To”标头分开。如果您查看 Exchange 的 wireshark 日志(即)发送如上所述的电子邮件,它将有两个端口 25(大概)会话,一次到 domain1,然后再到 domain2。在第一个会话中,RCPT TO 将是 someone1@domain1.com 并且 To 标头将是 To:someone1@domain1.com, somenone2@domain2.com。对于第二个会话,To 标头将相同,但 RCPT TO 将是 someone2@domain2.com。在 .net 类中,To 集合实际上是 RCPT TO,似乎我们无法访问 To 标头。当然,如果您尝试这样做并实际添加了两个收件人,domain1 将为某人@domain2.com 提供中继错误(反之亦然)。理想情况下,我们可以将 RCPT 集合设置为收件人,而 To(和 CC)集合可以是一个标头包装器,它可以根据 RCPT 信息默认设置,或者我们可以覆盖。就目前而言,没有办法使用 .net 类来真正实现自己的邮件服务器实现。

我已经为此苦苦挣扎了几年。它最近刚刚成为一个问题,因为我们开始使用 CC 和多个 Tos,所以我正在寻找解决方案。目前我正在考虑使用自定义套接字实现或使用 Rebex。他们似乎有我需要的东西,但我不能说我已经按照我的意愿让它工作了。当然,如果有一些很棒的反射技巧(就像我们对 FQDN 所做的那样)来使这项工作在本地进行,那将是很高兴知道的。简而言之,您的问题的答案是 AFAIK,不能这样做。我会发回我对 Rebex 的任何经验。

【讨论】:

    猜你喜欢
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 2021-10-27
    • 2019-03-26
    • 2021-06-13
    相关资源
    最近更新 更多