From 83551b0a469dba8c99b025924e124cd269b51149 Mon Sep 17 00:00:00 2001 From: Frank Yin Date: Wed, 24 Jan 2024 13:28:53 -0800 Subject: [PATCH 1/3] add custom headers support for emails --- pom.xml | 2 +- .../com/mailgun/form/CustomProperties.java | 20 +++++ .../java/com/mailgun/form/FormEncoder.java | 4 +- src/main/java/com/mailgun/form/PojoUtil.java | 88 +++++++++++++++++++ .../com/mailgun/model/message/Message.java | 22 +++++ 5 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/mailgun/form/CustomProperties.java create mode 100644 src/main/java/com/mailgun/form/PojoUtil.java diff --git a/pom.xml b/pom.xml index 64ccced..5fb7a8e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.mailgun mailgun-java - 1.1.1 + 1.1.2 jar ${project.groupId}:${project.artifactId} diff --git a/src/main/java/com/mailgun/form/CustomProperties.java b/src/main/java/com/mailgun/form/CustomProperties.java new file mode 100644 index 0000000..cb65226 --- /dev/null +++ b/src/main/java/com/mailgun/form/CustomProperties.java @@ -0,0 +1,20 @@ +package com.mailgun.form; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Target(FIELD) +@Retention(RUNTIME) +public @interface CustomProperties { + + /** + * The name of the property. + */ + String prefix (); + +} diff --git a/src/main/java/com/mailgun/form/FormEncoder.java b/src/main/java/com/mailgun/form/FormEncoder.java index 8b9978a..8a47df4 100644 --- a/src/main/java/com/mailgun/form/FormEncoder.java +++ b/src/main/java/com/mailgun/form/FormEncoder.java @@ -16,8 +16,8 @@ import feign.form.util.CharsetUtil; import lombok.val; -import static feign.form.util.PojoUtil.isUserPojo; -import static feign.form.util.PojoUtil.toMap; +import static com.mailgun.form.PojoUtil.isUserPojo; +import static com.mailgun.form.PojoUtil.toMap; import static java.util.Arrays.asList; public class FormEncoder implements Encoder { diff --git a/src/main/java/com/mailgun/form/PojoUtil.java b/src/main/java/com/mailgun/form/PojoUtil.java new file mode 100644 index 0000000..a75f049 --- /dev/null +++ b/src/main/java/com/mailgun/form/PojoUtil.java @@ -0,0 +1,88 @@ +package com.mailgun.form; + +import feign.form.FormProperty; +import lombok.*; +import lombok.experimental.FieldDefaults; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.rmi.UnexpectedException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; + +import static java.lang.reflect.Modifier.isFinal; +import static java.lang.reflect.Modifier.isStatic; +import static lombok.AccessLevel.PRIVATE; + +/** + * + * @author Artem Labazin + */ +public final class PojoUtil { + + public static boolean isUserPojo (@NonNull Object object) { + val type = object.getClass(); + val packageName = type.getPackage().getName(); + return !packageName.startsWith("java."); + } + + public static boolean isUserPojo (@NonNull Type type) { + val typeName = type.toString(); + return !typeName.startsWith("class java."); + } + + @SneakyThrows + public static Map toMap (@NonNull Object object) { + val result = new HashMap(); + val type = object.getClass(); + val setAccessibleAction = new PojoUtil.SetAccessibleAction(); + for (val field : type.getDeclaredFields()) { + val modifiers = field.getModifiers(); + if (isFinal(modifiers) || isStatic(modifiers)) { + continue; + } + setAccessibleAction.setField(field); + AccessController.doPrivileged(setAccessibleAction); + + val fieldValue = field.get(object); + if (fieldValue == null) { + continue; + } + if (field.isAnnotationPresent(CustomProperties.class)) { + String prefix = field.getAnnotation(CustomProperties.class).prefix(); + Map properties = (Map) fieldValue; + for (Map.Entry entry : properties.entrySet()) { + result.put(prefix + entry.getKey(), entry.getValue()); + } + } else { + val propertyKey = field.isAnnotationPresent(FormProperty.class) + ? field.getAnnotation(FormProperty.class).value() + : field.getName(); + + result.put(propertyKey, fieldValue); + } + + } + return result; + } + + private PojoUtil () throws UnexpectedException { + throw new UnexpectedException("It is not allowed to instantiate this class"); + } + + @Setter + @NoArgsConstructor + @FieldDefaults(level = PRIVATE) + private static class SetAccessibleAction implements PrivilegedAction { + + Field field; + + @Override + public Object run () { + field.setAccessible(true); + return null; + } + } +} diff --git a/src/main/java/com/mailgun/model/message/Message.java b/src/main/java/com/mailgun/model/message/Message.java index 8433737..f4d4388 100644 --- a/src/main/java/com/mailgun/model/message/Message.java +++ b/src/main/java/com/mailgun/model/message/Message.java @@ -6,6 +6,7 @@ import java.util.Map; import java.util.Set; +import com.mailgun.form.CustomProperties; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -287,6 +288,14 @@ public class Message { @FormProperty("t:variables") String mailgunVariables; + /** + *

+ * Specify custom email headers + *

+ */ + @CustomProperties(prefix = "h:") + Map headers; + public static MessageBuilder builder() { return new CustomMessageBuilder(); } @@ -768,6 +777,19 @@ public MessageBuilder mailgunVariables(String mailgunVariables) { this.mailgunVariables = mailgunVariables; return this; } + + /** + *

+ * Specify custom email headers + *

+ * + * @param headers custom email headers + * @return Returns a reference to this object so that method calls can be chained together. + */ + public MessageBuilder headers(Map headers) { + this.headers = headers; + return this; + } } } From d0c52fc089be6e6015389e2409abc1a7daccb4a9 Mon Sep 17 00:00:00 2001 From: Frank Yin Date: Fri, 26 Jan 2024 11:58:03 -0800 Subject: [PATCH 2/3] update readme and changelog --- CHANGELOG.md | 5 +++++ README.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f5fb30..0d8786d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All _notable_ changes to this project will be documented in this file. The format is based on _[Keep a Changelog][keepachangelog]_, and this project adheres to _[Semantic Versioning][semver]_. +## [1.1.2] (released: 2024-01-26) +### Updated +- add ability for MailgunMessagesApi to support arbitrary email headers through `.headers`. + ## [1.1.1] (released: 2023-12-12) ### Updated - add ability for primary accounts to make API calls on behalf of their subaccounts, e.g. sending messages, managing mailing lists, etc. @@ -67,6 +71,7 @@ adheres to _[Semantic Versioning][semver]_. - Add Import a list of bounces from CSV file API +[1.1.2]: https://github.com/mailgun/mailgun-java/compare/release/1.1.1...release/1.1.2 [1.1.1]: https://github.com/mailgun/mailgun-java/compare/release/1.1.0...release/1.1.1 [1.1.0]: https://github.com/mailgun/mailgun-java/compare/release/1.0.9...release/1.1.0 [1.0.9]: https://github.com/mailgun/mailgun-java/compare/release/1.0.8...release/1.0.9 diff --git a/README.md b/README.md index a992980..837e790 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Add the following to your `pom.xml`: com.mailgun mailgun-java - 1.1.1 + 1.1.2 ... @@ -85,7 +85,7 @@ Add the following to your `pom.xml`: Gradle Groovy DSL . ```xml -implementation 'com.mailgun:mailgun-java:1.1.1' +implementation 'com.mailgun:mailgun-java:1.1.2' ``` From b6cf1fc9116577ba773a65e742ac79b675436e0d Mon Sep 17 00:00:00 2001 From: Frank Yin Date: Thu, 1 Feb 2024 00:18:45 -0800 Subject: [PATCH 3/3] fix imports --- src/main/java/com/mailgun/form/PojoUtil.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mailgun/form/PojoUtil.java b/src/main/java/com/mailgun/form/PojoUtil.java index a75f049..3bb935b 100644 --- a/src/main/java/com/mailgun/form/PojoUtil.java +++ b/src/main/java/com/mailgun/form/PojoUtil.java @@ -1,8 +1,12 @@ package com.mailgun.form; import feign.form.FormProperty; -import lombok.*; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.Setter; +import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; +import lombok.val; import java.lang.reflect.Field; import java.lang.reflect.Type;