将一个收件人添加到邮件,但将标头添加到电子邮件客户端会看到所有收件人

本文关键字:添加 收件人 电子邮件 客户端 一个 | 更新日期: 2023-09-27 18:36:23

我目前正在做一个C#项目,在那里我正在制作自己的SMTP服务器。它的工作更少,但我正在尝试让它工作,我可以向不同域上的多个收件人发送电子邮件。

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

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

如果不同的域但通过谷歌应用服务器,我会得到ALT2.ASPMX.L.GOOGLE.COM的MX记录。当发送邮件时,虽然上面添加的收件人谷歌会发回一个错误,因为他们不允许通过一个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;
}

感谢您提供的任何帮助。

将一个收件人添加到邮件,但将标头添加到电子邮件客户端会看到所有收件人

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

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

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