我目前正在从事一个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.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;
}
谢谢你能提供的帮助。
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的任何经历发回来。