We've seen a few similar questions on StackOverflow before regarding System.Web.Helpers.Webmail.Send but I see no proper explanation for what's going on.
Regarding the to: parameter, the documentation says:
The email address of the recipient or recipients. Separate multiple recipients using a semicolon (;).
and I've seen answers saying "use a comma because the docs are wrong", or "use a semicolon", or "maybe it's an environment issue".
The code
WebMail.Send(
to: "joe.bloggs#mail.com,jane.bloggs#mail.com",
from: "no-reply#company.com",
subject: "Some Automated Email",
body: "<strong>Lorem Ipsum</strong>",
isBodyHtml: true
);
I've tried a few scenarios:
joe.bloggs#mail.com;jane.bloggs#mail.com
No emails recieved: An invalid character was found in the mail header: ';'.
joe.bloggs#mail.com; jane.bloggs#mail.com
Only the first recipient receives the email
joe.bloggs#mail.com,jane.bloggs#mail.com
both recieved the email
joe.bloggs#mail.com, jane.bloggs#mail.com
both recieved the email
joe.bloggs#mail.com, non-existant#mail.com
First recieved the email, but uncaught exception: Mailbox unavailable. The server response was: 5.7.1 Unable to relay
non-existant#mail.com, joe.bloggs#mail.com
No emails recieved: An invalid character was found in the mail header: ','.
Can anybody shed some light on this? I've actually had even more bizzare behaviour on a different server; I'm using Exchange for the above tests, but actually experienced different behaviour on hMailServer where joe.bloggs#mail.com,jane.bloggs#mail.com resulted in a silent failure with no server errors and no outgoing mail in hMailServer logs. On the system with hMailServer I have only had success with a single address.
This probably has to do with the variety of relays you are connecting to, and the variety of methods they accept. Not only do the delimiter characters matter to each specific mail server, but the e-mail addresses also do (since different relays will be configure to accept certain e-mails, and will throw a variety of error codes back for bad e-mails, which will in turn throw a variety of exceptions).
The System.Net.Mail namespace has a MailMessage object that contains MailAddressCollection objects for To, CC, and Bcc that you can just call Add() on for each recipient.
I have a library that sends mail (without a relay) that uses it (everything goes to Bcc), you can check the code out there. If you happen to use the library, be sure to keep your IP address in good reputation and make sure your DNS records are all setup the same way you would if you were a relay (PTR and A records all setup).
As I understand it, the mistake in the documentation is the likely scenario. I don't have this assembly, so I can't confirm it in ILSpy, but apparently the helper class simply uses System.Net.Mail. Following the four parameter overload through I get to this internal method.
internal Message(string from, string to) : this()
{
//...
this.to = new MailAddressCollection
{
to
}
}
As a result, it simply creates a new MailAddressCollection which requires a comma delimiter. At no point did the to string ever replace or manipulate a semi-colon (unless this is done within the Helper class but that doesn't appear to be the case).
Related
I would like to send an email from within sharepoint to a user on the local domain, after an event reciever has been triggered.
How would I go about this?
Any help would be much appreciated.
Many Thanks,
Freddie
You didn't really gave much context to your question, so I'm just going to point out the simplest alternative.
In most situations, you should be just be able to use one of the SPUtility.SendMail(..) overloads
So, something like this should be sufficient
var headers = new StringDictionary();
headers.Add("from", from);
headers.Add("to", to);
headers.Add("cc", cc);
headers.Add("bcc", bcc);
headers.Add("subject", subject);
headers.Add("content-type", "text/html");
SPUtility.SendEmail(web, headers, body);
That said, keep in mind that SPUtility.SendEmail isn't very robust (sometimes, it won't even point out if an error occurred while sending the mail...).
For this reason, some sources prefer to just use the well documented SmtpClient instead. In that case, the only problematic part is getting the outbound email server address.
SmtpClient client = new SmtpClient();
client.Host = currentWeb.Site.WebApplication.OutboundMailServiceInstance.Server.Address;
As you can see, one possible option is getting it from the web application associated to the current web site (that is, assuming you have a valid SPContext at the time and are therefore able to access the current web site in the first place). From here, just build the MailMessage instance and send it using client.Send(message);.
I am currently evaluating the redemption library for converting MSG files to EML files.
RDOSession session = new RDOSession();
RDOMail msg = session.GetMessageFromMsgFile(msgFile);
msg.SaveAs(emlFile, rdoSaveAsType.olRFC822);
So far Redemption is doing a really good job here in contrast to everything else I've tested against our "wild MSG-files corpus".
Nevertheless there is an issue with internal e-mail addresses. For internal e-mail addresses the resulting EML-file does contain the personal part of the addresses only but not the real e-mail address with the # sign.
I can see that RDOMail's recipient objects contains the real e-mail address in the SMTPAddress property in any case.
But there is a difference for the Address property which contains the "real e-mail address" for external addresses but something like /O=EXAMPLE ORGANIZAION/OU=SOME GROUP/cn=Recipients/cn=FBarney for internal addresses.
The latter ones are exactly the addresses that are missing the real e-mail address in the resulting EML-file.
So I tried to override the Address property like that:
recipient.Address = recipient.SMTPAddress;
But this does not have any effect on the resulting EML-file at the end.
How to convert MSG to EML with redemption without losing the real e-mail addresses for internal addresses?
This is an indication that EX type addresses cannot be converted to SMTP. This usually happens if the current MAPI session does not have access to the Exchange server that hosts these GAL objects. In your particular case, there is no MAPI session at all. You can either set the RDOSession.MAPIOBJECT property to Namespace.MAPIOBJECT from the Outlook Object Model to share the session with Outlook or you can call RDOSession.Logon/LogonExchangeMailbox/etc.
You can also try to specify the olRfc822_Redemption format to force Redemption to use its internal MIME convertor (it jumps through quite a few hoops to get the SMTP addresses from the message itself rather than GAL). By default olRfc822 uses the built-in Outlook convertor (IConvertorSession) if Outlook is installed.
I know there are various thread out there related to this problem but i was unable to take any of the responses on those thread and make it work on my server.
So let try to see if someone can help me out here.
99% of the emails go out properly and few actually return with that error.
My code looks like this
MailMessage mm = new MailMessage(Settings.EmailCustomerService, to, subject, body);
mm.SubjectEncoding = Encoding.UTF8;
mm.BodyEncoding = Encoding.UTF8;
mm.IsBodyHtml = true;
MailAddress add = new MailAddress(Settings.EmailCustomerService, "Customer Service");
mm.From = add;
try
{
SmtpClient client = new SmtpClient(Settings.EmailSMTP);
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(Settings.EmailUser, Settings.EmailPwd);
System.Threading.ParameterizedThreadStart threadStart = new System.Threading.ParameterizedThreadStart(SendInThread);
threadStart.Invoke(new SendInThreadParams
{
client = client,
Message = mm
});
}
finally
{
mm = null;
}
Actually the Credentials code was added later but my code was run OK even without it. It just happen that 1% of the email never make it to the recipients and adding those 2 lines for Credentials did not make a difference.
The Settings.EmailUser is just a user on the server where the SMTP runs, but i have NOT attach it to nowhere.
I bet that's the problem.
The SMTP Server Relay is set to use 127.0.0.1 and the FQDN is just the name of the machine (something like "Machine1" ...nothing with a domain.com name)
The error I'm getting is this
Reporting-MTA: dns;Machine1
Received-From-MTA: dns;Machine1
Arrival-Date: Wed, 30 May 2012 23:08:36 -0700
Final-Recipient: rfc822;test#email.net
Action: failed
Status: 5.5.0
Diagnostic-Code: smtp;550 Access denied - Invalid HELO name (See RFC2821 4.1.1.1)
Return message emailed back was:
> This is an automatically generated Delivery Status Notification.
Delivery to the following recipients failed.
test#email.com
Thanks in advanced...
In addition to the message/delivery-status attachment, the DSN will usually have the returned message. For this sort of issue you should post the headers of the returned message and the DSN as well.
It looks to me like your server has accepted the message, but has an error transmitting it onwards. If your server had rejected it, your code would have thrown an exception. So your server Machine1 accepted it, attempted to transmit it to email.net, but email.net rejected it. Machine1 then generated a DSN (delivery status notification, in your case an NDR = Non-Delivery Report).
In other words it is a configuration error with the email server not a code problem. Almost certainly the issue is that the email server is not set up with an FQDN as you stated.
As a configuration problem, it belongs on ServerFault.
Based on BEN answer I realized that I was missing the PRIMARY DND SUFFIX.
Mainly in order to find out your FQDN, you need to simply:
1) Open a Command Prompt
2) Type "ipconfig /all"
Read your HOST NAME + PRIMARY DNS SUFFIX.
My DNS SUFFIX was emtpy so i went and added using this link
http://www.simpledns.com/kb.aspx?kbid=1227
And then rebooted the machine.
Now the code works like a charm.
Thanks BEN !!!
I am implementing a mailing list using using .NET. As discussed in this answer, I need to send an email where the recipient of the envelope is different from the recipient in the To header. How to achieve this in C#? The SmtpClient and MailMessage classes in System.Net.Mail doens't seem to permit this.
I tried:
message.To.Add("list#example.com");
message.Headers["Envelope-to"] = "user#example.com";
but the mail doesn't get sent to what it is specified in the Envelope-to.
Any suggestions?
Adding an address to Envelope-To without adding it to To
You can use the MailMessage.Bcc property. Addresses added there will only appear in the Envelope-To, not in the mail's To:
message.Bcc.Add("user#example.com");
Adding an address to To without adding it to Envelope-To
Here, I'm quite sure you are out of luck. I've had a look at the System.Net.Mail namespace with ILSpy, and it looks like this is not possible. The To header of the mail is created out of the To property of the MailMessage (see Message.PrepareHeaders), and the same property is used to fill the Envelope-To of the mail (together with the Cc and Bcc properties, see SmtpClient.Send). Manually setting Headers["To"] won't help, since this value is overwritten with the contents of the To property (see Message.PrepareHeaders).
So, list#example.com will get a copy of the message. Depending on the configuration of your SMTP server, this might lead to a mail loop.
I'm creating a new mail definition using the CreateMailMessage function of a MailDefinition. One of the required parameters is recipients. The documentation for this function states that recipients is to be a comma-separated list of recipients, however when I try to send a message to multiple users I am getting the following error:
An invalid character was found in the mail header: ','...
So it seems like this function is not working as intended. Normally I would add all the recipients to the mail message itself, but unfortunately the recipients parameter is required and cannot be left blank. Any ideas?
I got it working but unfortunately its more of a hack than anything.
I take one email address from the "to" field and set it as the recipient in CreateMailMessage, which returns a MailMessage instance.
I take the produced MailMessage and add all the email addresses in my MailAddressCollection by iterating through the construct. I also do this for all CC'd users.