Skip to content

Instantly share code, notes, and snippets.

@flameoftheforest
Last active July 21, 2023 09:35
Show Gist options
  • Save flameoftheforest/83b398d386c458d86c504cf09d1e07e2 to your computer and use it in GitHub Desktop.
Save flameoftheforest/83b398d386c458d86c504cf09d1e07e2 to your computer and use it in GitHub Desktop.
MailGun Netcore Multipart-Form Data Example (with attachment handling)
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
namespace TEST00
{
public class TestClass
{
private IAmazonS3 S3;
const string DOMAIN = "theBigRobot.org";
const string API_KEY = "key-bigrobotkey";
public void Test00()
{
PostToMailGun("[email protected]", "The Big Robot", "[email protected]", "Greeting from Big Robot", "hello, Big Robot greets you.", "<html>hello, <b>Big Robot</b> greets you.</html>");
}
/// <summary>
/// This sample code demonstrates a few things:
/// - Using HttpClient to POST a multipart form.
/// - POST the said form to MailGun.
/// - Attaching files to the MailGun submission.
/// - Using Amazon S3 Client.
///
/// Implementation References (with thanks):
/// https://github.com/restsharp/RestSharp/wiki/Recommended-Usage
/// https://stackoverflow.com/questions/16906711/httpclient-how-to-upload-multiple-files-at-once
/// https://github.com/Vodurden/Http-Multipart-Data-Parser
///
/// </summary>
/// <param name="recipientEmail"></param>
/// <param name="senderName"></param>
/// <param name="senderEmail"></param>
/// <param name="subject"></param>
/// <param name="textBody"></param>
/// <param name="htmlBody"></param>
private void PostToMailGun(string recipientEmail, string senderName, string senderEmail, string subject, string textBody, string htmlBody)
{
HttpClient client = new HttpClient();
var encoded = Convert.ToBase64String(Encoding.ASCII.GetBytes($"api:{API_KEY}"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encoded);
var content = new MultipartFormDataContent();
content.Add(new StringContent(DOMAIN), "domain"); // may need url-encode
content.Add(new StringContent($"{senderName} <{senderEmail}>"), "from");
content.Add(new StringContent($"{recipientEmail}"), "to");
content.Add(new StringContent($"{subject}"), "subject");
content.Add(new StringContent($"{htmlBody}"), "html");
content.Add(new StringContent($"{textBody}"), "text");
// The arrangement of how attachments should be managed is heavily subjected to discussion.
// This only serves as a starting point and totally lacks flexibility.
S3Returns file1 = GetStreamFromS3("BUCKET", "Jesus.jpg");
content.Add(CreateAttachmentContent(file1.Stream, "Jesus.jpg", file1.ContentType));
S3Returns file2 = GetStreamFromS3("BUCKET", "why seek ye the living among the dead.jpg");
content.Add(CreateAttachmentContent(file2.Stream, "why_seek_ye.jpg", file2.ContentType));
HttpResponseMessage response = client.PostAsync($"https://api.mailgun.net/v3/{DOMAIN}/messages", content).Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception($"{response.ReasonPhrase}");
}
}
private StreamContent CreateAttachmentContent(Stream stream, string fileName, string contentType)
{
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"attachment[]\"",
FileName = "\"" + fileName + "\""
}; // the extra quotes are key here
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return fileContent;
}
private S3Returns GetStreamFromS3(string bucket, string key)
{
GetObjectRequest req = new GetObjectRequest
{
BucketName = bucket,
Key = key
};
GetObjectResponse resp = S3.GetObjectAsync(req).Result;
if (resp.HttpStatusCode != HttpStatusCode.OK)
{
throw new Exception("something's wrong");
}
return new S3Returns
{
Stream = resp.ResponseStream,
ContentType = resp.Headers.ContentType
};
}
public TestClass()
{
S3 = new AmazonS3Client("KEY", "SECRET", RegionEndpoint.SIBERIA);
}
}
internal class S3Returns
{
public Stream Stream { get; set; }
public string ContentType { get; set; }
}
}
@runtimesoftware
Copy link

Perfect! Thanks for sharing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment