Event Tech: Groovy, Mailgun & “Fiancé”

This is an Event Tech Post written by our Co-Founder and Lead Engineer, Andrew Garcia. Have an idea for a tech post? Email us: [email protected]

Event Tech & Goodshuffle Pro

Here at Goodshuffle we’ve built our entire platform using Grails (currently 3.3.1). Occasionally we run into interesting problems that hopefully by writing down here we can help save others out there a boatload of time. Truth be told, we should’ve started the tech portion of our blog a long time ago; it’s been a long journey.

Mailgun & HttpBuilder

Like I said we’ve been on Grails for a while (it’s a tidy package around Spring, Hibernate, using Groovy along with Java that runs on the JVM). We ran into an issue using HttpBuilder to make API calls to Mailgun. Our function was structured to pass & encode attachments which forced us to use MultipartEntityBuilder to specify the ‘parts’. And, for some reason, it took way longer than it should have to figure out how to properly set UTF-8 encoding.

Our platform is built for the event rental industry, so this was a big issue. A lot of communication is between rental companies and brides & grooms. Thus, the word “fiancé” is used frequently, as you can imagine. We needed to have special characters display properly in the messages that arrived via email.

I read the docs, saw Mailgun’s use of quoted-printable encoding and vanished into what felt like an unnecessary black hole of confusion. I attempted setting the content-type header in a billion places until finding/realizing where it was actually needed.

Anyhow, if you Googled “UTF-8 encoding Mailgun, Httpbuilder” and are looking for code on how to do it, here it is. Make sure you set the charset on the StringBody constructor call.

HTTPBuilder http = new HTTPBuilder("https://api.mailgun.net")http.request(Method.POST) { multipartRequest ->
uri.path = "/v3/" + mailGunDomain + "/messages"

 headers["Authorization"] = "Basic " + ("api:" + System.env.MAILGUN_SECRET_API_KEY).bytes.encodeBase64().toString() MultipartEntityBuilder multipartRequestEntity = MultipartEntityBuilder.create() multipartRequestEntity.addPart('from', new StringBody(sourceEmailAddress)) multipartRequestEntity.addPart('to', new StringBody(destinationEmail)) multipartRequestEntity.addPart('h:Reply-To', new StringBody(replyToEmail)) multipartRequestEntity.addPart('subject', new StringBody(title)) multipartRequestEntity.addPart('html', new StringBody(content, org.apache.http.entity.ContentType.TEXT_HTML.withCharset('UTF-8'))) attachments?.each { Map attachment -> log.info("adding mime attachment name=" + attachment.name + ", fileSize=" + ((byte[]) attachment.contents).length) multipartRequestEntity.addPart('attachment', new ByteArrayBody((byte[]) attachment.contents, attachment.name)) } multipartRequest.entity = multipartRequestEntity.build() response.success = { resp, json -> log.info("Successfully sent e-mail to Mailgun for processing. resp.message=" + json.message + ", messageID=" + json.id + ", to_email=" + destinationEmail + ", conversationHash=" + conversationHash) } response.failure = { resp, jsonMap -> throw new RuntimeException("Error occurred while sending transactional e-mail to mailgun. title=" + title + ", source_email=" + sourceEmail + ", destinationEmail=" + destinationEmail) } return true }