I'm searching for an working C# example to send attachments with Amazon-SES.
After reading that Amazon-SES now supports sending attachments I was searching for an C# example but was unable to find one.
I'm searching for an working C# example to send attachments with Amazon-SES.
After reading that Amazon-SES now supports sending attachments I was searching for an C# example but was unable to find one.
I think that using AWS SDK for .NET and MimeKit is very easy and clean solution. You can send e-mails with attachments via SES API (instead of SMTP).
You can write MimeMessage directly to MemoryStream and then use it with SES SendRawEmail:
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using Amazon;
using Amazon.Runtime;
using MimeKit;
private static BodyBuilder GetMessageBody()
{
var body = new BodyBuilder()
{
HtmlBody = @"<p>Amazon SES Test body</p>",
TextBody = "Amazon SES Test body",
};
body.Attachments.Add(@"c:\attachment.txt");
return body;
}
private static MimeMessage GetMessage()
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Foo Bar", "[email protected]"));
message.To.Add(new MailboxAddress(string.Empty, "[email protected]"));
message.Subject = "Amazon SES Test";
message.Body = GetMessageBody().ToMessageBody();
return message;
}
private static MemoryStream GetMessageStream()
{
var stream = new MemoryStream();
GetMessage().WriteTo(stream);
return stream;
}
private void SendEmails()
{
var credentals = new BasicAWSCredentials("<aws-access-key>", "<aws-secret-key>");
using (var client = new AmazonSimpleEmailServiceClient(credentals, RegionEndpoint.EUWest1))
{
var sendRequest = new SendRawEmailRequest { RawMessage = new RawMessage(GetMessageStream()) };
try
{
var response = client.SendRawEmail(sendRequest);
Console.WriteLine("The email was sent successfully.");
}
catch (Exception e)
{
Console.WriteLine("The email was not sent.");
Console.WriteLine("Error message: " + e.Message);
}
}
}
public Boolean SendRawEmail(String from, String to, String cc, String Subject, String text, String html, String replyTo, string attachPath)
{
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));
}
List<String> ccAddresses = cc.Replace(", ", ",").Split(',').Where(y => y != "").ToList();
foreach (String ccAddress in ccAddresses)
{
mailMessage.CC.Add(new MailAddress(ccAddress));
}
mailMessage.Subject = Subject;
mailMessage.SubjectEncoding = Encoding.UTF8;
if (replyTo != null)
{
mailMessage.ReplyToList.Add(new MailAddress(replyTo));
}
if (text != null)
{
mailMessage.AlternateViews.Add(plainView);
}
if (html != null)
{
mailMessage.AlternateViews.Add(htmlView);
}
if (attachPath.Trim() != "")
{
if (System.IO.File.Exists(attachPath))
{
System.Net.Mail.Attachment objAttach = new System.Net.Mail.Attachment(attachPath);
objAttach.ContentType = new ContentType("application/octet-stream");
System.Net.Mime.ContentDisposition disposition = objAttach.ContentDisposition;
disposition.DispositionType = "attachment";
disposition.CreationDate = System.IO.File.GetCreationTime(attachPath);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(attachPath);
disposition.ReadDate = System.IO.File.GetLastAccessTime(attachPath);
mailMessage.Attachments.Add(objAttach);
}
}
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(ConfigurationManager.AppSettings.Get("AccessKeyId"), ConfigurationManager.AppSettings.Get("SecretKeyId"));
try
{
SendRawEmailResponse response = ses.SendRawEmail(request);
SendRawEmailResult result = response.SendRawEmailResult;
return true;
}
catch (AmazonSimpleEmailServiceException ex)
{
return false;
}
}
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;
}
Found that here
Update: A method signature has changed in .NET 4.5, which breaks the above: Getting System.Net.Mail.MailMessage as a MemoryStream in .NET 4.5 beta
This is a very simple implementation using MimeKit
using Amazon;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using MimeKit;
using System.IO;
namespace SendEmailWithAttachments
{
class Program
{
static void Main(string[] args)
{
//Remember to enter your (AWSAccessKeyID, AWSSecretAccessKey) if not using and IAM User with credentials assigned to your instance and your RegionEndpoint
using (var client = new AmazonSimpleEmailServiceClient("YourAWSAccessKeyID", "YourAWSSecretAccessKey", RegionEndpoint.USEast1))
using (var messageStream = new MemoryStream())
{
var message = new MimeMessage();
var builder = new BodyBuilder() { TextBody = "Hello World" };
message.From.Add(new MailboxAddress("[email protected]"));
message.To.Add(new MailboxAddress("[email protected]"));
message.Subject = "Hello World";
//I'm using the stream method, but you don't have to.
using (FileStream stream = File.Open(@"Attachment1.pdf", FileMode.Open)) builder.Attachments.Add("Attachment1.pdf", stream);
using (FileStream stream = File.Open(@"Attachment2.pdf", FileMode.Open)) builder.Attachments.Add("Attachment2.pdf", stream);
message.Body = builder.ToMessageBody();
message.WriteTo(messageStream);
var request = new SendRawEmailRequest()
{
RawMessage = new RawMessage() { Data = messageStream }
};
client.SendRawEmail(request);
}
}
}
}
I have the code in my repository https://github.com/gianluis90/amazon-send-email
You can setup IIS SMTP to relay through SES as well.
You need to install stunnel and set it up
Then you can just set the IIS SMTP Smart Host and some other options and it will relay your email through SES.
Instructions from above linked gist:
Instructions taken from Amazon's docs and modified as necessary.
c:\program files (x86)\stunnel\stunnel.conf
file in notepadExample SSL server mode services
section, won't have a client = yes
line)[smtp-tls-wrapper]
accept = 127.0.0.1:2525
client = yes
connect = email-smtp.us-east-1.amazonaws.com:465
stunnel.exe
and ensure no errors are reported (you will get a little systray icon)stunnel.exe -install
at command line (note this installs the service but doesn't start it, so start it)telnet localhost 2525
and you should see an SMTP response from Amazon's server (if telnet isn't installed, add the feature in Server Manager / Features / Add Feature)[127.0.0.1]
(include the brackets)2525
(like the stunnel.conf file)I'm not sure if this is what you are looking for, but it's the only resource I've been able to find on the subject. I would love a better answer to this question, too.
http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/
It states how to use it, but is very cryptic, at least to me.
Any better guides out there?
I think you need to follow the instructions on this link. Amazon doesn't let you add attachments or other more complicated message types (iCalendar events). Essentially you need to handcraft the message body by string building and manipulation.
Currently I do this for iCalendar format emails on a legacy system. It's a bit of a pain in the ass, but if you read RFC 2822, it tells you pretty clearly what the format is. Special things to pay attention to:
Best of luck. I don't know if there is an open library that will do this sort of thing for you in C#. If you can find one then try use it, because dealing with the intricacies of the RFC should have a medical notice for increased blood pressure and hair loss.