diff --git a/README.md b/README.md
index b82fb5a..21eb661 100644
--- a/README.md
+++ b/README.md
@@ -159,6 +159,9 @@ MailerSend Java SDK
- [Update a blocklist monitor](#update-a-blocklist-monitor)
- [Delete a blocklist monitor](#delete-a-blocklist-monitor)
+- [WhatsApp](#whatsapp)
+ - [Send a WhatsApp message](#send-a-whatsapp-message)
+ - [Send a WhatsApp message with personalization](#send-a-whatsapp-message-with-personalization)
- [Testing](#testing)
- [Support and Feedback](#support-and-feedback)
- [License](#license)
@@ -172,12 +175,12 @@ Using Maven:
Constructor for MailerSend.
*/ @@ -73,6 +75,7 @@ public MailerSend() { scheduledMessages = new ScheduledMessages(this); emailVerification = new EmailVerification(this); sms = new Sms(this); + whatsapp = new WhatsApp(this); dmarcMonitoring = new DmarcMonitoring(this); blocklistMonitoring = new BlocklistMonitoring(this); smtpUsers = new SmtpUsers(this); @@ -217,7 +220,16 @@ public EmailVerification emailVerification() { public Sms sms() { return sms; } - + + /** + * Get the whatsapp access object + * + * @return The WhatsApp object + */ + public WhatsApp whatsapp() { + return whatsapp; + } + /** * Get the DMARC monitoring access object * diff --git a/src/main/java/com/mailersend/sdk/whatsapp/WhatsApp.java b/src/main/java/com/mailersend/sdk/whatsapp/WhatsApp.java new file mode 100644 index 0000000..594f3eb --- /dev/null +++ b/src/main/java/com/mailersend/sdk/whatsapp/WhatsApp.java @@ -0,0 +1,41 @@ +/************************************************* + * MailerSend Java SDK + * https://github.com/mailersend/mailersend-java + * + * @author MailerSendWhatsApp class.
+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsApp { + + private MailerSend apiObjectReference; + private WhatsAppBuilder builder; + + /** + *Constructor for WhatsApp.
+ * + * @param ref a {@link com.mailersend.sdk.MailerSend} object. + */ + public WhatsApp(MailerSend ref) { + apiObjectReference = ref; + builder = new WhatsAppBuilder(ref); + } + + /** + *builder.
+ * + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppBuilder} object. + */ + public WhatsAppBuilder builder() { + return builder; + } +} diff --git a/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppBuilder.java b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppBuilder.java new file mode 100644 index 0000000..d6d3ced --- /dev/null +++ b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppBuilder.java @@ -0,0 +1,120 @@ +/************************************************* + * MailerSend Java SDK + * https://github.com/mailersend/mailersend-java + * + * @author MailerSendWhatsAppBuilder class.
+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsAppBuilder { + + private WhatsAppBuilderBody builderBody; + private MailerSend apiObjectReference; + + /** + *Constructor for WhatsAppBuilder.
+ * + * @param ref a {@link com.mailersend.sdk.MailerSend} object. + */ + public WhatsAppBuilder(MailerSend ref) { + apiObjectReference = ref; + builderBody = new WhatsAppBuilderBody(); + } + + /** + *from.
+ * + * @param from the sender to send from, either a connected WhatsApp sender's phone number in E.164 format or its MailerSend sender ID + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppBuilder} object. + */ + public WhatsAppBuilder from(String from) { + builderBody.from = from; + return this; + } + + /** + *addRecipient.
+ * + * @param recipient a phone number in E.164 format, or a BSUID taken from an inbound message + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppBuilder} object. + */ + public WhatsAppBuilder addRecipient(String recipient) { + builderBody.to.add(recipient); + return this; + } + + /** + *templateId.
+ * + * @param templateId the ID of the approved WhatsApp template + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppBuilder} object. + */ + public WhatsAppBuilder templateId(String templateId) { + builderBody.templateId = templateId; + return this; + } + + /** + *addPersonalization.
+ * + * @param personalization a {@link com.mailersend.sdk.whatsapp.WhatsAppPersonalization} object. + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppBuilder} object. + */ + public WhatsAppBuilder addPersonalization(WhatsAppPersonalization personalization) { + if (builderBody.personalization == null) { + builderBody.personalization = new ArrayListsend.
+ * + * @return the ID of the created message + * @throws com.mailersend.sdk.exceptions.MailerSendException if any. + */ + public String send() throws MailerSendException { + String endpoint = "/whatsapp/send"; + + MailerSendApi api = new MailerSendApi(); + api.setToken(apiObjectReference.getToken()); + + Gson gson = new GsonBuilder() + .addSerializationExclusionStrategy(new JsonSerializationDeserializationStrategy(false)) + .addDeserializationExclusionStrategy(new JsonSerializationDeserializationStrategy(true)) + .create(); + + String json = gson.toJson(builderBody); + + builderBody = new WhatsAppBuilderBody(); + + WhatsAppSendResponse response = api.postRequest(endpoint, json, WhatsAppSendResponse.class); + + if (response.messageId != null && !response.messageId.isBlank()) { + return response.messageId; + } + + if (response.data != null) { + return response.data.id; + } + + return null; + } +} diff --git a/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppBuilderBody.java b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppBuilderBody.java new file mode 100644 index 0000000..abc80c6 --- /dev/null +++ b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppBuilderBody.java @@ -0,0 +1,33 @@ +/************************************************* + * MailerSend Java SDK + * https://github.com/mailersend/mailersend-java + * + * @author MailerSendWhatsAppBuilderBody class.
+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsAppBuilderBody { + + @SerializedName("from") + public String from; + + @SerializedName("to") + public ArrayListWhatsAppPersonalization class.
+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsAppPersonalization { + + @SerializedName("to") + public String to; + + @SerializedName("data") + public WhatsAppPersonalizationData data = new WhatsAppPersonalizationData(); + + /** + *Constructor for WhatsAppPersonalization.
+ * + * @param to the recipient the values apply to, as listed in the message's recipients + */ + public WhatsAppPersonalization(String to) { + this.to = to; + } + + /** + *setHeader.
+ * + * @param header array of header variable values + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppPersonalization} object. + */ + public WhatsAppPersonalization setHeader(String[] header) { + this.data.header = header; + return this; + } + + /** + *setBody.
+ * + * @param body array of body variable values + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppPersonalization} object. + */ + public WhatsAppPersonalization setBody(String[] body) { + this.data.body = body; + return this; + } + + /** + *setButtons.
+ * + * @param buttons array of button variable values + * @return a {@link com.mailersend.sdk.whatsapp.WhatsAppPersonalization} object. + */ + public WhatsAppPersonalization setButtons(String[] buttons) { + this.data.buttons = buttons; + return this; + } +} diff --git a/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppPersonalizationData.java b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppPersonalizationData.java new file mode 100644 index 0000000..e74cc65 --- /dev/null +++ b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppPersonalizationData.java @@ -0,0 +1,28 @@ +/************************************************* + * MailerSend Java SDK + * https://github.com/mailersend/mailersend-java + * + * @author MailerSendWhatsAppPersonalizationData class.
+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsAppPersonalizationData { + + @SerializedName("header") + public String[] header; + + @SerializedName("body") + public String[] body; + + @SerializedName("buttons") + public String[] buttons; +} diff --git a/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppSendResponse.java b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppSendResponse.java new file mode 100644 index 0000000..aa31562 --- /dev/null +++ b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppSendResponse.java @@ -0,0 +1,23 @@ +/************************************************* + * MailerSend Java SDK + * https://github.com/mailersend/mailersend-java + * + * @author MailerSendWhatsAppSendResponse class.
+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsAppSendResponse extends MailerSendResponse { + + @SerializedName("data") + public WhatsAppSendResponseData data; +} diff --git a/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppSendResponseData.java b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppSendResponseData.java new file mode 100644 index 0000000..de16da2 --- /dev/null +++ b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppSendResponseData.java @@ -0,0 +1,22 @@ +/************************************************* + * MailerSend Java SDK + * https://github.com/mailersend/mailersend-java + * + * @author MailerSendWhatsAppSendResponseData class.
+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsAppSendResponseData { + + @SerializedName("id") + public String id; +} diff --git a/src/test/java/com/mailersend/sdk/tests/WhatsAppTests.java b/src/test/java/com/mailersend/sdk/tests/WhatsAppTests.java new file mode 100644 index 0000000..4fa4f51 --- /dev/null +++ b/src/test/java/com/mailersend/sdk/tests/WhatsAppTests.java @@ -0,0 +1,98 @@ +package com.mailersend.sdk.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; + +import com.mailersend.sdk.MailerSend; +import com.mailersend.sdk.exceptions.MailerSendException; +import com.mailersend.sdk.whatsapp.WhatsAppPersonalization; +import com.mailersend.sdk.vcr.VcrRecorder; + +public class WhatsAppTests { + + @BeforeEach + public void setupEach(TestInfo info) throws IOException { + VcrRecorder.useRecording("WhatsAppTests_" + info.getDisplayName()); + } + + @AfterEach + public void afterEach() throws IOException { + VcrRecorder.stopRecording(); + } + + @Test + public void TestSendWhatsApp() { + MailerSend ms = new MailerSend(); + ms.setToken(TestHelper.validToken); + + try { + String messageId = ms.whatsapp().builder() + .from("12345678901") + .addRecipient("19191234567") + .templateId("template_id_123") + .send(); + + assertEquals("67f91abd69f79df391e9d78d", messageId); + + } catch (MailerSendException e) { + fail(); + } + } + + @Test + public void TestSendWhatsAppWithPersonalization() { + MailerSend ms = new MailerSend(); + ms.setToken(TestHelper.validToken); + + try { + WhatsAppPersonalization p1 = new WhatsAppPersonalization("19191234567") + .setHeader(new String[]{"John"}) + .setBody(new String[]{"order #1234", "tomorrow"}) + .setButtons(new String[]{"https://example.com/track/1234"}); + + WhatsAppPersonalization p2 = new WhatsAppPersonalization("19199876543") + .setHeader(new String[]{"Jane"}) + .setBody(new String[]{"order #5678", "Friday"}); + + String messageId = ms.whatsapp().builder() + .from("12345678901") + .addRecipient("19191234567") + .addRecipient("19199876543") + .templateId("template_id_123") + .addPersonalization(p1) + .addPersonalization(p2) + .send(); + + assertEquals("67f91b2c69f79df391e9d791", messageId); + + } catch (MailerSendException e) { + fail(); + } + } + + @Test + public void TestSendWhatsAppWithoutMessageIdHeader() { + MailerSend ms = new MailerSend(); + ms.setToken(TestHelper.validToken); + + try { + String messageId = ms.whatsapp().builder() + .from("12345678901") + .addRecipient("19191234567") + .templateId("template_id_123") + .send(); + + assertEquals("67f91abd69f79df391e9d78d", messageId); + + } catch (MailerSendException e) { + fail(); + } + } +} diff --git a/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsApp().json b/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsApp().json new file mode 100644 index 0000000..6feb226 --- /dev/null +++ b/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsApp().json @@ -0,0 +1 @@ +{"2bb7d30db82f0eb4ba655eee85d9d4faa9859778": {"body": "{\"data\":{\"id\":\"67f91abd69f79df391e9d78d\",\"created_at\":\"2026-08-31 07:24:20\"}}", "headers": {":status": ["202"], "cache-control": ["no-cache, private"], "content-type": ["application/json"], "date": ["Mon, 31 Aug 2026 07:24:20 GMT"], "x-message-id": ["67f91abd69f79df391e9d78d"], "x-ratelimit-limit": ["60"], "x-ratelimit-remaining": ["59"]}, "statusCode": 202}} \ No newline at end of file diff --git a/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsAppWithPersonalization().json b/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsAppWithPersonalization().json new file mode 100644 index 0000000..6a1ad0d --- /dev/null +++ b/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsAppWithPersonalization().json @@ -0,0 +1 @@ +{"fd5817b4599977adf389348739c54d7d68b3ccf0": {"body": "{\"data\":{\"id\":\"67f91b2c69f79df391e9d791\",\"created_at\":\"2026-08-31 07:26:04\"}}", "headers": {":status": ["202"], "cache-control": ["no-cache, private"], "content-type": ["application/json"], "date": ["Mon, 31 Aug 2026 07:24:20 GMT"], "x-message-id": ["67f91b2c69f79df391e9d791"], "x-ratelimit-limit": ["60"], "x-ratelimit-remaining": ["59"]}, "statusCode": 202}} \ No newline at end of file diff --git a/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsAppWithoutMessageIdHeader().json b/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsAppWithoutMessageIdHeader().json new file mode 100644 index 0000000..285b563 --- /dev/null +++ b/src/test/resources/fixtures/WhatsAppTests_TestSendWhatsAppWithoutMessageIdHeader().json @@ -0,0 +1 @@ +{"2bb7d30db82f0eb4ba655eee85d9d4faa9859778": {"body": "{\"data\":{\"id\":\"67f91abd69f79df391e9d78d\",\"created_at\":\"2026-08-31 07:24:20\"}}", "headers": {":status": ["202"], "cache-control": ["no-cache, private"], "content-type": ["application/json"], "date": ["Mon, 31 Aug 2026 07:24:20 GMT"], "x-ratelimit-limit": ["60"], "x-ratelimit-remaining": ["58"]}, "statusCode": 202}} \ No newline at end of file