augur
augur

Reputation: 246

Create mime email message from scratch (for Mailgun API)

How can I compose mime email message in Java (or Kotlin)? I don't understand how to use javax.mail.internet.MimeMessage because I don't have smtp, but https endpoint (using Mailgun service).

Below code sends multipart/form-data request, but in target mailbox there is just plain text received (html not rendered), without "Subject" and proper "From".

So it appears that I have to embed this in mimeMessage, that I attach as form-data. But how?

val fileMap: MultiValueMap<String, String> = LinkedMultiValueMap()
val contentDisposition = ContentDisposition
        .builder("form-data")
        .name("message")
        .filename("message.mime")
        .build()
fileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString())

val mimeMessage = "<html>some <b>nice</b> html</html>".toByteArray() // <<-- How to build this properly?
val fileEntity = HttpEntity<ByteArray>(mimeMessage, fileMap)

val headers = HttpHeaders()
headers.contentType = MediaType.MULTIPART_FORM_DATA

val parts: MultiValueMap<String, Any> = LinkedMultiValueMap()
parts.add("file", fileEntity)
parts.add("from", mailProperties.fromAddress)
parts.add("to", email.to)
parts.add("subject", email.subject)

val requestEntity: HttpEntity<MultiValueMap<String, Any>> = HttpEntity(parts, headers)
val res = restTemplate.postForEntity("https://api.eu.mailgun.net/v3/mydomain.com/messages.mime", requestEntity, String::class.java)

Upvotes: 0

Views: 772

Answers (2)

Joseph L.
Joseph L.

Reputation: 1

I had to do this a similar way in Java. The Mailgun API docs here mention "# multipart/form-data is not supported yet" for Java requests, but I think the process is just a bit involved. There are ways to condense this and the request building part can be split out, but this should work as well.

import javax.mail.internet.MimeMessage;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import java.io.ByteArrayOutputStream;
import java.util.UUID;
import java.nio.charset.StandardCharsets;

public void createAndSendEmail(MimeMessage mimeMessage, String toRecipients) {
    // Create request
    String mimeMessageUuid = UUID.randomUUID().toString();

    String boundary = "uuid--" + mimeMessageUuid;

    StringBuilder builder = new StringBuilder();
    builder.append("--").append(boundary).append("\r\n");
    builder.append("Content-Disposition: form-data; name=\"to\"\r\n\r\n");
    builder.append(toRecipients).append("\r\n");
    builder.append("--").append(boundary).append("\r\n");
    builder.append("Content-Disposition: form-data; name=\"message\"; filename=\"message.eml\"\r\n");
    builder.append("Content-Type: message/rfc822\r\n\r\n");

    String body = builder.toString();
    String footer = "\r\n--" + boundary + "--\r\n";

    // Convert MimeMessage to ByteArrayOutputStream
    ByteArrayOutputStream mimeMessageOutputStream = new ByteArrayOutputStream();

    // Combine parts
    ByteArrayOutputStream requestBody = new ByteArrayOutputStream();
    try {
        mimeMessage.writeTo(mimeMessageOutputStream);
        requestBody.write(body.getBytes(StandardCharsets.UTF_8));
        requestBody.write(mimeMessageOutputStream.toByteArray());
        requestBody.write(footer.getBytes(StandardCharsets.UTF_8));
    } catch (Exception e) {
        throw new RuntimeException("MimeMessage is malformed!");
    }

    // Send email via Mailgun HTTP endpoint
    try (Response response = client.target("https://api.mailgun.net/v3/{domain_name}/messages.mime")
                                   .request()
                                   .header(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=" + boundary)
                                   .header(HttpHeaders.AUTHORIZATION, "Basic " + String.format("%s:%s", USERNAME, API_KEY))
                                   .post(Entity.entity(requestBody.toByteArray(), "multipart/form-data; boundary=" + boundary))) {
        if (response.getStatus() == 200) {
            System.out.println("SUCCESS");
        }
        // other HTTP statuses checked here
    }
}

Upvotes: 0

augur
augur

Reputation: 246

Well, I found the way to compose correct mime message and then send it as multipart/form-data. Looks not too clean, but at least it works:

In the original code, instead of:

val mimeMessage = "<html>some <b>nice</b> html</html>".toByteArray()

I did the following:

val impl = JavaMailSenderImpl()
val msg = impl.createMimeMessage()
val helper = MimeMessageHelper(msg, true)
helper.setFrom(mailProperties.fromAddress)
helper.addTo(email.to)
helper.setSubject(email.subject)
helper.setText("<html>some <b>nice</b> html</html>", true)
val out = ByteArrayOutputStream()
helper.mimeMessage.writeTo(out)
val mimeMessage = out.toByteArray()

Upvotes: 0

Related Questions