Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Send SMS messages with Azure Communication Services SMS Java SDK. Use when implementing SMS notifications, alerts, OTP delivery, bulk messaging, or delivery reports.
.claude/skills/azure-communication-sms-java/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-18 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-13 | ✗→✓ | ▲ Improved | — | — |
| case-22 | ✗→✓ | ▲ Improved | — | — |
| case-20 | ✗→✓ | ▲ Improved | — | — |
Send SMS messages to single or multiple recipients with delivery reporting.
xml<dependency> <groupId>com.azure</groupId> <artifactId>azure-communication-sms</artifactId> <version>1.2.0</version> </dependency>
javaimport com.azure.communication.sms.SmsClient; import com.azure.communication.sms.SmsClientBuilder; import com.azure.identity.DefaultAzureCredentialBuilder; // With DefaultAzureCredential (recommended) SmsClient smsClient = new SmsClientBuilder() .endpoint("https://<resource>.communication.azure.com") .credential(new DefaultAzureCredentialBuilder().build()) .buildClient(); // With connection string SmsClient smsClient = new SmsClientBuilder() .connectionString("<connection-string>") .buildClient(); // With AzureKeyCredential import com.azure.core.credential.AzureKeyCredential; SmsClient smsClient = new SmsClientBuilder() .endpoint("https://<resource>.communication.azure.com") .credential(new AzureKeyCredential("<access-key>")) .buildClient(); // Async client SmsAsyncClient smsAsyncClient = new SmsClientBuilder() .connectionString("<connection-string>") .buildAsyncClient();
javaimport com.azure.communication.sms.models.SmsSendResult; // Simple send SmsSendResult result = smsClient.send( "+14255550100", // From (your ACS phone number) "+14255551234", // To "Your verification code is 123456"); System.out.println("Message ID: " + result.getMessageId()); System.out.println("To: " + result.getTo()); System.out.println("Success: " + result.isSuccessful()); if (!result.isSuccessful()) { System.out.println("Error: " + result.getErrorMessage()); System.out.println("Status: " + result.getHttpStatusCode()); }
javaimport com.azure.communication.sms.models.SmsSendOptions; import java.util.Arrays; import java.util.List; List<String> recipients = Arrays.asList( "+14255551111", "+14255552222", "+14255553333" ); // With options SmsSendOptions options = new SmsSendOptions() .setDeliveryReportEnabled(true) .setTag("marketing-campaign-001"); Iterable<SmsSendResult> results = smsClient.sendWithResponse( "+14255550100", // From recipients, // To list "Flash sale! 50% off today only.", options, Context.NONE ).getValue(); for (SmsSendResult result : results) { if (result.isSuccessful()) { System.out.println("Sent to " + result.getTo() + ": " + result.getMessageId()); } else { System.out.println("Failed to " + result.getTo() + ": " + result.getErrorMessage()); } }
javaSmsSendOptions options = new SmsSendOptions(); // Enable delivery reports (sent via Event Grid) options.setDeliveryReportEnabled(true); // Add custom tag for tracking options.setTag("order-confirmation-12345");
javaimport com.azure.core.http.rest.Response; Response<Iterable<SmsSendResult>> response = smsClient.sendWithResponse( "+14255550100", Arrays.asList("+14255551234"), "Hello!", new SmsSendOptions().setDeliveryReportEnabled(true), Context.NONE ); // Check HTTP response System.out.println("Status code: " + response.getStatusCode()); System.out.println("Headers: " + response.getHeaders()); // Process results for (SmsSendResult result : response.getValue()) { System.out.println("Message ID: " + result.getMessageId()); System.out.println("Successful: " + result.isSuccessful()); if (!result.isSuccessful()) { System.out.println("HTTP Status: " + result.getHttpStatusCode()); System.out.println("Error: " + result.getErrorMessage()); } }
javaimport reactor.core.publisher.Mono; SmsAsyncClient asyncClient = new SmsClientBuilder() .connectionString("<connection-string>") .buildAsyncClient(); // Send single message asyncClient.send("+14255550100", "+14255551234", "Async message!") .subscribe( result -> System.out.println("Sent: " + result.getMessageId()), error -> System.out.println("Error: " + error.getMessage()) ); // Send to multiple with options SmsSendOptions options = new SmsSendOptions() .setDeliveryReportEnabled(true); asyncClient.sendWithResponse( "+14255550100", Arrays.asList("+14255551111", "+14255552222"), "Bulk async message", options) .subscribe(response -> { for (SmsSendResult result : response.getValue()) { System.out.println("Result: " + result.getTo() + " - " + result.isSuccessful()); } });
javaimport com.azure.core.exception.HttpResponseException; try { SmsSendResult result = smsClient.send( "+14255550100", "+14255551234", "Test message" ); // Individual message errors don't throw exceptions if (!result.isSuccessful()) { handleMessageError(result); } } catch (HttpResponseException e) { // Request-level failures (auth, network, etc.) System.out.println("Request failed: " + e.getMessage()); System.out.println("Status: " + e.getResponse().getStatusCode()); } catch (RuntimeException e) { System.out.println("Unexpected error: " + e.getMessage()); } private void handleMessageError(SmsSendResult result) { int status = result.getHttpStatusCode(); String error = result.getErrorMessage(); if (status == 400) { System.out.println("Invalid phone number: " + result.getTo()); } else if (status == 429) { System.out.println("Rate limited - retry later"); } else { System.out.println("Error " + status + ": " + error); } }
Delivery reports are sent via Azure Event Grid. Configure an Event Grid subscription for your ACS resource.
java// Event Grid webhook handler (in your endpoint) public void handleDeliveryReport(String eventJson) { // Parse Event Grid event // Event type: Microsoft.Communication.SMSDeliveryReportReceived // Event data contains: // - messageId: correlates to SmsSendResult.getMessageId() // - from: sender number // - to: recipient number // - deliveryStatus: "Delivered", "Failed", etc. // - deliveryStatusDetails: detailed status // - receivedTimestamp: when status was received // - tag: your custom tag from SmsSendOptions }
| Property | Type | Description | |----------|------|-------------| | getMessageId() | String | Unique message identifier | | getTo() | String | Recipient phone number | | isSuccessful() | boolean | Whether send succeeded | | getHttpStatusCode() | int | HTTP status for this recipient | | getErrorMessage() | String | Error details if failed | | getRepeatabilityResult() | RepeatabilityResult | Idempotency result |
bashAZURE_COMMUNICATION_ENDPOINT=https://<resource>.communication.azure.com AZURE_COMMUNICATION_CONNECTION_STRING=endpoint=https://...;accesskey=... SMS_FROM_NUMBER=+14255550100
+[country code][number]isSuccessful() for each recipient individuallyThis skill is applicable to execute the workflow or actions described in the overview.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.