我目前正在开发一个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.com
和someone@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;
}
感谢您提供的任何帮助。
答案 0 :(得分:1)
董事会,首先,让我说我理解你为什么要做自己的SMTP服务器而不是中继。我们正在做同样的事情,因为我们需要实时处理电子邮件故障,而不必依赖于badmail或NDR。只有控制传输通道才能实现。
您遇到的问题是无法将RCPT TO命令与“To”标题分开。如果您查看有关Exchange的wireshark日志(即)发送如上所述的电子邮件,它将有两个端口25(可能是)会话,一次到domain1,再次到domain2。在第一个会话中, RCPT TO 将 someone1@domain1.com 并且To标题将为 To:someone1 @ domain1.com,somenone2 @ domain2.com < / em>的。对于第二个会话,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的任何经验。