Skip to content

Instantly share code, notes, and snippets.

@stickfigure
Created September 5, 2023 20:53
Show Gist options
  • Save stickfigure/848b4c6728ea76847abb169b3d341d1d to your computer and use it in GitHub Desktop.
Save stickfigure/848b4c6728ea76847abb169b3d341d1d to your computer and use it in GitHub Desktop.
Java code to convert data: urls in html email to multipart/related mime messages with content id links
package com.orbitkit.blah.blah;
import com.google.common.base.Preconditions;
import com.google.common.io.BaseEncoding;
import lombok.SneakyThrows;
import lombok.Value;
import lombok.With;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.ArrayList;
import java.util.List;
public class ImageReplacer {
@Value @With
public static class Replaced {
/** With data: urls replaced by cids */
String message;
/** The resulting image parts, with unique cids */
List<ImagePart> images;
@SneakyThrows
public MimeMessage toMimeMessage() {
final MimeMessage mimeMessage = new MimeMessage((Session)null);
final MimeMultipart multipartRelated = new MimeMultipart("related");
mimeMessage.setContent(multipartRelated);
final MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(message, "text/html; charset=utf-8");
multipartRelated.addBodyPart(htmlPart);
for (final ImagePart image : images) {
final byte[] imageBytes = BaseEncoding.base64().decode(image.getBase64());
final MimeBodyPart imagePart = new MimeBodyPart();
imagePart.setContentID(image.getCid());
imagePart.setContent(imageBytes, image.getContentType());
multipartRelated.addBodyPart(imagePart);
}
return mimeMessage;
}
}
@Value
public static class ImagePart {
String cid;
String contentType;
String base64;
}
public static Replaced replace(final String message) {
final StringBuilder bld = new StringBuilder();
final List<ImagePart> images = new ArrayList<>();
int here = 0;
while (true) {
final int blockStart = message.indexOf("src=\"data:", here);
if (blockStart < 0) {
break;
}
final int dataStart = blockStart + "src=\"".length();
// Everything up to the start of the data url
bld.append(message, here, dataStart);
final int dataEnd = message.indexOf("\"", dataStart);
Preconditions.checkState(dataEnd > dataStart);
final String dataUrl = message.substring(dataStart, dataEnd);
final ImagePart part = partFromDataUrl(dataUrl, images.size());
images.add(part);
bld.append("cid:").append(part.getCid()).append('"');
here = dataEnd + 1;
}
bld.append(message, here, message.length());
return new Replaced(bld.toString(), images);
}
private static ImagePart partFromDataUrl(final String dataUrl, final int imageIndex) {
final String[] splitProtocol = dataUrl.split(":");
Preconditions.checkArgument(splitProtocol.length == 2);
Preconditions.checkArgument(splitProtocol[0].equals("data"));
final String startsWithContentType = splitProtocol[1];
final String[] splitContentType = startsWithContentType.split(";");
Preconditions.checkArgument(splitContentType.length == 2);
final String contentType = splitContentType[0];
final String startsWithBase64 = splitContentType[1];
final String[] splitBase64 = startsWithBase64.split(",");
Preconditions.checkArgument(splitBase64.length == 2);
Preconditions.checkArgument(splitBase64[0].equals("base64"));
final String base64Data = splitBase64[1];
return new ImagePart("image" + imageIndex, contentType, base64Data);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment