提问者:小点点

将一个收件人添加到MailMessage但将标题添加到电子邮件客户端查看所有收件人


我目前正在从事一个C#项目,我正在制作自己的SMTP服务器。这是一个比较少的工作,但我正试图使它的工作,我可以发送电子邮件给多个收件人,在不同的领域。

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

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会话。所以只有一条消息。到为我收到的每个收件人添加。我想做的是添加一个标题,这样它仍然可以显示电子邮件收件人仍然要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;
}

谢谢你能提供的帮助。


共1个答案

匿名用户

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

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

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