In my last post, I promised to look at SendRawEmail next. I got busy on other projects so this has taken longer than I originally anticipated it would.
Converting MailMessage into a MemoryStream
public static MemoryStream ConvertMailMessageToMemoryStream(MailMessage message)
{
Assembly assembly = typeof(SmtpClient).Assembly;
Type mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
MemoryStream fileStream = new MemoryStream();
ConstructorInfo mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
object mailWriter = mailWriterContructor.Invoke(new object[] { fileStream });
MethodInfo sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true }, null);
MethodInfo closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
return fileStream;
}
When we create a request for the SES service, we need to give it a MemoryStream object that contains our mail message. I created a MailMessage object for this, but in order to give this to SES I had to convert it to a MemoryStream. I found the guts of the method above online, and slightly modified it for my own use. I’m not going to talk about it, but you can find it here.
SendRawEmail
public static Boolean SendRawEmail(String from, String to, String Subject, String text = null, String html = null, String replyTo = null, String returnPath = null)
{
AlternateView plainView = AlternateView.CreateAlternateViewFromString(text, Encoding.UTF8, "text/plain");
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(html, Encoding.UTF8, "text/html");
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress(from);
List<String> toAddresses = to.Replace(", ", ",").Split(',').ToList();
foreach (String toAddress in toAddresses)
{
mailMessage.To.Add(new MailAddress(toAddress));
}
//foreach (String ccAddress in ccAddresses)
//{
// mailMessage.CC.Add(new MailAddress(ccAddress));
//}
//foreach (String bccAddress in bccAddresses)
//{
// mailMessage.Bcc.Add(new MailAddress(bccAddress));
//}
mailMessage.Subject = Subject;
mailMessage.SubjectEncoding = Encoding.UTF8;
if (replyTo != null)
{
mailMessage.ReplyTo = new MailAddress(replyTo);
}
if (text != null)
{
mailMessage.AlternateViews.Add(plainView);
}
if (html != null)
{
mailMessage.AlternateViews.Add(htmlView);
}
RawMessage rawMessage = new RawMessage();
using (MemoryStream memoryStream = ConvertMailMessageToMemoryStream(mailMessage))
{
rawMessage.WithData(memoryStream);
}
SendRawEmailRequest request = new SendRawEmailRequest();
request.WithRawMessage(rawMessage);
request.WithDestinations(toAddresses);
request.WithSource(from);
AmazonSimpleEmailService ses = AWSClientFactory.CreateAmazonSimpleEmailServiceClient(AppConfig["AWSAccessKey"], AppConfig["AWSSecretKey"]);
try
{
SendRawEmailResponse response = ses.SendRawEmail(request);
SendRawEmailResult result = response.SendRawEmailResult;
Console.WriteLine("Email sent.");
Console.WriteLine(String.Format("Message ID: {0}", result.MessageId));
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
The above method uses the .NET MailMessage class to create my email message.
Lines 3/4 create our alternative email messages so the email should be visible in whatever mail app is used to retrieve the emails.
Lines 9-13 add the TO addresses to the mail message. Again, I pass in the emails as a string separated by a semi-colon and convert this to a list. The mail message wants each address added as a MailAddress object so a foreach loop steps through the list and adds each address correctly.
Lines 15-23 do the same for CC and BCC address if you wanted to use them. I haven’t in my example, but include the code commented out for you. You’ll also need to add them so you can pass them in when calling the method (Line 1).
Line 25/26 sets the Subject and its encoding and then lines 28-41 add the Reply To address and our alternative views we created earlier (if the String isn’t null).
Line 43 creates our RawMessage object and then lines 45-48 call our method above to convert the MailMessage into a MemoryStream.
We create our request on line 50 and give it our RawMessage on line 51. We also give it our TO addresses and our FROM address on lines 53/54.
We connect to SES on line 56 and then get the response from giving SES our request on lines 60-62 and output to the console the Message ID and a confimation message on lines 64/65.
Other than converting the MailMessage to a MemoryStream this is pretty straight forward. I’ll do my best to help anyone having issues via the comments…
Neil
5 Comments
Thank you very much for examples.
ReplyDeleteI tried to add a support of attachments but it seems there are nuances which i dont know.
string file = @"C:\Users\boss\Documents\Visual Studio 2008\Projects\AmazonSES\arrow_left.jpg";
Attachment data = new Attachment(file, new ContentType( "multipart/mixed" ) );
// Add time stamp information for the file.
ContentDisposition disposition = data.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(file);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(file);
disposition.ReadDate = System.IO.File.GetLastAccessTime(file);
mailMessage.Attachments.Add( data );
It fires exception : [Amazon.SimpleEmail.AmazonSimpleEmailServiceException] = {"Illegal content disposition 'attachment' in content type 'multipart/mixed'."}
Hi Alex.
ReplyDeleteUnfortunately, at present Amazon does not support attachments in Simple Email Service (SES). I suspect that this is something they are working on but you'll have to wait until they update the service and APIs.
See here: https://forums.aws.amazon.com/thread.jspa?threadID=59037&tstart=0
Sorry about that,
Neil
After contacting Alex via his email address, I was able to help him out. I posted the answer to the link he provided.
ReplyDeleteNeil, I have a need where I need to either get notified than an email has arrived or simply go through the inbox and retrieve the from address and the attachment. Any hints or a blog would tremendously help.
ReplyDeleteThanks.
Hi Frank,
ReplyDeleteYou mention an inbox, but not what inbox you mean. The Amazon SES service doesn't have an inbox, its just meant as a Mail Server for sending mails through. In order to receive replies, you'd need a mail account elsewhere to be set up.
Depending on the mail account your using, it should be fairly simple to do what you asked say in GMail etc.
Have I understood you correctly?
:)