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: com.mailersend java-sdk - 2.1.0 + 2.2.0 Using Gradle: - implementation 'com.mailersend:java-sdk:2.1.0' + implementation 'com.mailersend:java-sdk:2.2.0' # Usage @@ -4533,6 +4536,79 @@ public void deleteInvite() { } ``` +# WhatsApp + +`from` takes a connected WhatsApp sender, either as its phone number in E.164 format or as its MailerSend sender ID. A sender connected with a Meta virtual number has no phone number, so it can only be addressed by its sender ID. Recipients are phone numbers in E.164 format, or a BSUID taken from an inbound message. Sending requires a token with the `whatsapp_full` scope. + +### Send a WhatsApp message + +```java +import com.mailersend.sdk.MailerSend; +import com.mailersend.sdk.exceptions.MailerSendException; + +public void sendWhatsApp() { + + MailerSend ms = new MailerSend(); + ms.setToken("mailersend token"); + + try { + + String messageId = ms.whatsapp().builder() + .from("12345678901") + .addRecipient("19191234567") + .templateId("your_template_id") + .send(); + + System.out.println(messageId); + + } catch (MailerSendException e) { + + e.printStackTrace(); + } +} +``` + +### Send a WhatsApp message with personalization + +```java +import com.mailersend.sdk.MailerSend; +import com.mailersend.sdk.exceptions.MailerSendException; +import com.mailersend.sdk.whatsapp.WhatsAppPersonalization; + +public void sendWhatsAppWithPersonalization() { + + MailerSend ms = new MailerSend(); + ms.setToken("mailersend token"); + + 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("your_template_id") + .addPersonalization(p1) + .addPersonalization(p2) + .send(); + + System.out.println(messageId); + + } catch (MailerSendException e) { + + e.printStackTrace(); + } +} +``` + # Testing To run the tests you need **Java 11+** and **Maven 3.6+** installed. diff --git a/pom.xml b/pom.xml index 40e8d8e..4ac3e8b 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.mailersend java-sdk - 2.1.0 + 2.2.0 MailerSend Java SDK An SDK for MailerSend API https://github.com/mailersend/mailersend-java diff --git a/src/main/java/com/mailersend/sdk/MailerSend.java b/src/main/java/com/mailersend/sdk/MailerSend.java index 23cad3e..25017ff 100644 --- a/src/main/java/com/mailersend/sdk/MailerSend.java +++ b/src/main/java/com/mailersend/sdk/MailerSend.java @@ -17,6 +17,7 @@ import com.mailersend.sdk.scheduledmessages.ScheduledMessages; import com.mailersend.sdk.sms.Sms; import com.mailersend.sdk.templates.Templates; +import com.mailersend.sdk.whatsapp.WhatsApp; import com.mailersend.sdk.tokens.Tokens; import com.mailersend.sdk.webhooks.Webhooks; import com.mailersend.sdk.emailverification.EmailVerification; @@ -49,12 +50,13 @@ public class MailerSend { private ScheduledMessages scheduledMessages = null; private EmailVerification emailVerification = null; private Sms sms = null; + private WhatsApp whatsapp = null; private DmarcMonitoring dmarcMonitoring = null; private BlocklistMonitoring blocklistMonitoring = null; private SmtpUsers smtpUsers = null; private SenderIdentities senderIdentities = null; private Users users = null; - + /** *

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 MailerSend + * https://mailersend.com + **************************************************/ +package com.mailersend.sdk.whatsapp; + +import com.mailersend.sdk.MailerSend; + +/** + *

WhatsApp 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 MailerSend + * https://mailersend.com + **************************************************/ +package com.mailersend.sdk.whatsapp; + +import java.util.ArrayList; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.mailersend.sdk.MailerSend; +import com.mailersend.sdk.MailerSendApi; +import com.mailersend.sdk.exceptions.MailerSendException; +import com.mailersend.sdk.util.JsonSerializationDeserializationStrategy; + +/** + *

WhatsAppBuilder 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 ArrayList(); + } + builderBody.personalization.add(personalization); + return this; + } + + /** + *

send.

+ * + * @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 MailerSend + * https://mailersend.com + **************************************************/ +package com.mailersend.sdk.whatsapp; + +import java.util.ArrayList; + +import com.google.gson.annotations.SerializedName; + +/** + *

WhatsAppBuilderBody class.

+ * + * @author mailersend + * @version $Id: $Id + */ +public class WhatsAppBuilderBody { + + @SerializedName("from") + public String from; + + @SerializedName("to") + public ArrayList to = new ArrayList(); + + @SerializedName("template_id") + public String templateId; + + @SerializedName("personalization") + public ArrayList personalization = null; +} diff --git a/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppPersonalization.java b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppPersonalization.java new file mode 100644 index 0000000..80f28e7 --- /dev/null +++ b/src/main/java/com/mailersend/sdk/whatsapp/WhatsAppPersonalization.java @@ -0,0 +1,67 @@ +/************************************************* + * MailerSend Java SDK + * https://github.com/mailersend/mailersend-java + * + * @author MailerSend + * https://mailersend.com + **************************************************/ +package com.mailersend.sdk.whatsapp; + +import com.google.gson.annotations.SerializedName; + +/** + *

WhatsAppPersonalization 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 MailerSend + * https://mailersend.com + **************************************************/ +package com.mailersend.sdk.whatsapp; + +import com.google.gson.annotations.SerializedName; + +/** + *

WhatsAppPersonalizationData 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 MailerSend + * https://mailersend.com + **************************************************/ +package com.mailersend.sdk.whatsapp; + +import com.google.gson.annotations.SerializedName; +import com.mailersend.sdk.MailerSendResponse; + +/** + *

WhatsAppSendResponse 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 MailerSend + * https://mailersend.com + **************************************************/ +package com.mailersend.sdk.whatsapp; + +import com.google.gson.annotations.SerializedName; + +/** + *

WhatsAppSendResponseData 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