Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating Java SDK to include inline attachments #41591

Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions sdk/communication/azure-communication-email/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
# Release History

## 1.1.0-beta.1 (Unreleased)
## 1.1.0-beta.1 (2024-08-14)

### Features Added

### Breaking Changes

### Bugs Fixed

- An `EmailMessage` with null recipient addresses can no longer be sent.

### Other Changes

- Consumers can now provide a value for the `ContentId` property when sending emails with attachments.
This allows consumers to reference attachments in the email body using the `cid` scheme. The `ContentId` property can be set on the `EmailAttachment` object.

## 1.0.15 (2024-07-26)

Expand Down
34 changes: 34 additions & 0 deletions sdk/communication/azure-communication-email/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This package contains the Java SDK for Azure Communication Services for Email.
To create these resources, you can use the [Azure Portal][communication_resource_create_portal], the [Azure PowerShell][communication_resource_create_power_shell], or the [.NET management client library][communication_resource_create_net].

### Include the package

#### Include the BOM file

Please include the azure-sdk-bom to your project to take dependency on the General Availability (GA) version of the library. In the following snippet, replace the {bom_version_to_target} placeholder with the version number.
Expand Down Expand Up @@ -46,20 +47,24 @@ and then include the direct dependency in the dependencies section without the v
```

#### Include direct dependency

If you want to take dependency on a particular version of the library that is not present in the BOM,
add the direct dependency to your project as follows.

[//]: # ({x-version-update-start;com.azure:azure-communication-email;current})

```xml
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-communication-email</artifactId>
<version>1.0.4</version>
</dependency>
```

[//]: # ({x-version-update-end})

## Key concepts

> More details coming soon.

## Examples
Expand Down Expand Up @@ -91,6 +96,7 @@ EmailClient emailClient = new EmailClientBuilder()
```

### Azure Active Directory Token Authentication

A `DefaultAzureCredential` object must be passed to the `EmailClientBuilder` via the `credential()` method. An endpoint must also be set via the `endpoint()` method.

The `AZURE_CLIENT_SECRET`, `AZURE_CLIENT_ID`, and `AZURE_TENANT_ID` environment variables are needed to create a `DefaultAzureCredential` object.
Expand Down Expand Up @@ -187,7 +193,35 @@ PollResponse<EmailSendResult> response = poller.waitForCompletion();
System.out.println("Operation Id: " + response.getValue().getId());
```

### Send Email with Inline Attachments

Azure Communication Services support sending inline attachments.
Adding an optional `contentId` parameter to an `EmailAttachment` will make the attachment an inline attachment.

```java readme-sample-sendEmailWithInlineAttachment
BinaryData attachmentContent = BinaryData.fromFile(new File("C:/attachment.txt").toPath());
EmailAttachment attachment = new EmailAttachment(
"inlineimage.jpg",
"image/jpeg",
attachmentContent
);
attachment.setContentId("inline_image");

EmailMessage message = new EmailMessage()
.setSenderAddress("<sender-email-address>")
.setToRecipients("<recipient-email-address>")
.setSubject("test subject")
.setBodyHtml("<h1>test message<img src=\"cid:inline_image\"></h1>")
.setAttachments(attachment);

SyncPoller<EmailSendResult, EmailSendResult> poller = emailClient.beginSend(message);
PollResponse<EmailSendResult> response = poller.waitForCompletion();

System.out.println("Operation Id: " + response.getValue().getId());
```

## Troubleshooting

> More details coming soon,

## Next steps
Expand Down
2 changes: 1 addition & 1 deletion sdk/communication/azure-communication-email/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "java",
"TagPrefix": "java/communication/azure-communication-email",
"Tag": "java/communication/azure-communication-email_e70471d340"
"Tag": "java/communication/azure-communication-email_50f2f82209"
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

import java.time.Duration;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Objects;

Expand Down Expand Up @@ -93,11 +92,21 @@ PollerFlux<EmailSendResult, EmailSendResult> beginSend(EmailMessage message, Con
if (message.getAttachments() != null) {
attachmentsImpl = new ArrayList<>();
for (EmailAttachment attachment: message.getAttachments()) {
attachmentsImpl.add(new com.azure.communication.email.implementation.models.EmailAttachment(
com.azure.communication.email.implementation.models.EmailAttachment attachmentImpl = null;

attachmentImpl = new com.azure.communication.email.implementation.models.EmailAttachment(
attachment.getName(),
attachment.getContentType(),
Base64.getEncoder().encodeToString(attachment.getContent().toBytes())
));
attachment.getContentInBase64()
);

String contentId = attachment.getContentId();

if (contentId != null) {
attachmentImpl.setContentId(contentId);
}

attachmentsImpl.add(attachmentImpl);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@

import com.azure.core.util.ServiceVersion;

/** Service version of AzureCommunicationServicesClient. */
/** Service version of EmailCommunicationServicesClient. */
public enum EmailServiceVersion implements ServiceVersion {
/** Enum value 2023-03-31. */
V2023_03_31("2023-03-31");
V2023_03_31("2023-03-31"),

/** Enum value 2024-07-01-preview. */
V2024_07_01_Preview("2024-07-01-preview");

private final String version;

Expand All @@ -28,6 +31,6 @@ public String getVersion() {
* @return The latest {@link EmailServiceVersion}.
*/
public static EmailServiceVersion getLatest() {
return V2023_03_31;
return V2024_07_01_Preview;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ public AzureCommunicationEmailServiceImplBuilder retryPolicy(RetryPolicy retryPo
public AzureCommunicationEmailServiceImpl buildClient() {
this.validateClient();
HttpPipeline localPipeline = (pipeline != null) ? pipeline : createHttpPipeline();
String localApiVersion = (apiVersion != null) ? apiVersion : "2023-03-31";
String localApiVersion = (apiVersion != null) ? apiVersion : "2024-07-01-preview";
SerializerAdapter localSerializerAdapter
= (serializerAdapter != null) ? serializerAdapter : JacksonAdapter.createDefaultSerializerAdapter();
AzureCommunicationEmailServiceImpl client = new AzureCommunicationEmailServiceImpl(localPipeline,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public final class EmailsImpl {

/**
* Initializes an instance of EmailsImpl.
*
*
natekimball-msft marked this conversation as resolved.
Show resolved Hide resolved
* @param client the instance of the service client containing this operation class.
*/
EmailsImpl(AzureCommunicationEmailServiceImpl client) {
Expand Down Expand Up @@ -82,7 +82,7 @@ Mono<EmailsSendResponse> send(@HostParam("endpoint") String endpoint,

/**
* Gets the status of the email send operation.
*
*
* @param operationId ID of the long running operation (GUID) returned from a previous call to send email.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ErrorResponseException thrown if the request is rejected by server.
Expand All @@ -98,7 +98,7 @@ public Mono<EmailsGetSendResultResponse> getSendResultWithResponseAsync(String o

/**
* Gets the status of the email send operation.
*
*
* @param operationId ID of the long running operation (GUID) returned from a previous call to send email.
* @param context The context to associate with this operation.
* @throws IllegalArgumentException thrown if parameters fail the validation.
Expand All @@ -115,7 +115,7 @@ public Mono<EmailsGetSendResultResponse> getSendResultWithResponseAsync(String o

/**
* Gets the status of the email send operation.
*
*
* @param operationId ID of the long running operation (GUID) returned from a previous call to send email.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ErrorResponseException thrown if the request is rejected by server.
Expand All @@ -129,7 +129,7 @@ public Mono<EmailSendResult> getSendResultAsync(String operationId) {

/**
* Gets the status of the email send operation.
*
*
* @param operationId ID of the long running operation (GUID) returned from a previous call to send email.
* @param context The context to associate with this operation.
* @throws IllegalArgumentException thrown if parameters fail the validation.
Expand All @@ -144,7 +144,7 @@ public Mono<EmailSendResult> getSendResultAsync(String operationId, Context cont

/**
* Queues an email message to be sent to one or more recipients.
*
*
* @param message Message payload for sending an email.
* @param operationId This is the ID provided by the customer to identify the long running operation. If an ID is
* not provided by the customer, the service will generate one.
Expand All @@ -164,7 +164,7 @@ public Mono<EmailsSendResponse> sendWithResponseAsync(EmailMessage message, UUID

/**
* Queues an email message to be sent to one or more recipients.
*
*
* @param message Message payload for sending an email.
* @param operationId This is the ID provided by the customer to identify the long running operation. If an ID is
* not provided by the customer, the service will generate one.
Expand All @@ -185,7 +185,7 @@ public Mono<EmailsSendResponse> sendWithResponseAsync(EmailMessage message, UUID

/**
* Queues an email message to be sent to one or more recipients.
*
*
* @param message Message payload for sending an email.
* @param operationId This is the ID provided by the customer to identify the long running operation. If an ID is
* not provided by the customer, the service will generate one.
Expand All @@ -208,7 +208,7 @@ public PollerFlux<EmailSendResult, EmailSendResult> beginSendAsync(EmailMessage

/**
* Queues an email message to be sent to one or more recipients.
*
*
* @param message Message payload for sending an email.
* @param operationId This is the ID provided by the customer to identify the long running operation. If an ID is
* not provided by the customer, the service will generate one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

package com.azure.communication.email.implementation.models;

import com.azure.core.annotation.Immutable;
import com.azure.core.annotation.Fluent;
import com.azure.core.util.BinaryData;
import com.azure.json.JsonReader;
import com.azure.json.JsonSerializable;
import com.azure.json.JsonToken;
Expand All @@ -16,7 +17,7 @@
/**
* Attachment to the email.
*/
@Immutable
@Fluent
public final class EmailAttachment implements JsonSerializable<EmailAttachment> {
/*
* Name of the attachment
Expand All @@ -31,7 +32,12 @@ public final class EmailAttachment implements JsonSerializable<EmailAttachment>
/*
* Base64 encoded contents of the attachment
*/
private final String contentInBase64;
private final BinaryData contentInBase64;

/*
* Unique identifier (CID) to reference an inline attachment.
*/
private String contentId;

/**
* Creates an instance of EmailAttachment class.
Expand All @@ -40,7 +46,7 @@ public final class EmailAttachment implements JsonSerializable<EmailAttachment>
* @param contentType the contentType value to set.
* @param contentInBase64 the contentInBase64 value to set.
*/
public EmailAttachment(String name, String contentType, String contentInBase64) {
public EmailAttachment(String name, String contentType, BinaryData contentInBase64) {
this.name = name;
this.contentType = contentType;
this.contentInBase64 = contentInBase64;
Expand All @@ -64,15 +70,46 @@ public String getContentType() {
return this.contentType;
}

/**
* @deprecated Use {@link #getContentInBase64()} instead.
* Returns the content of the attachment.
*
* @return The content of the attachment as BinaryData.
*/
@Deprecated
public BinaryData getContent() {
return this.contentInBase64;
}

/**
* Get the contentInBase64 property: Base64 encoded contents of the attachment.
*
* @return the contentInBase64 value.
*/
public String getContentInBase64() {
public BinaryData getContentInBase64() {
return this.contentInBase64;
}

/**
* Get the contentId property: Unique identifier (CID) to reference an inline attachment.
*
* @return the contentId value.
*/
public String getContentId() {
return this.contentId;
}

/**
* Set the contentId property: Unique identifier (CID) to reference an inline attachment.
*
* @param contentId the contentId value to set.
* @return the EmailAttachment object itself.
*/
public EmailAttachment setContentId(String contentId) {
this.contentId = contentId;
return this;
}

/**
* {@inheritDoc}
*/
Expand All @@ -81,7 +118,8 @@ public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
jsonWriter.writeStartObject();
jsonWriter.writeStringField("name", this.name);
jsonWriter.writeStringField("contentType", this.contentType);
jsonWriter.writeStringField("contentInBase64", this.contentInBase64);
jsonWriter.writeStringField("contentInBase64", this.contentInBase64.toString());
jsonWriter.writeStringField("contentId", this.contentId);
return jsonWriter.writeEndObject();
}

Expand All @@ -101,7 +139,8 @@ public static EmailAttachment fromJson(JsonReader jsonReader) throws IOException
boolean contentTypeFound = false;
String contentType = null;
boolean contentInBase64Found = false;
String contentInBase64 = null;
BinaryData contentInBase64 = null;
String contentId = null;
while (reader.nextToken() != JsonToken.END_OBJECT) {
String fieldName = reader.getFieldName();
reader.nextToken();
Expand All @@ -113,14 +152,19 @@ public static EmailAttachment fromJson(JsonReader jsonReader) throws IOException
contentType = reader.getString();
contentTypeFound = true;
} else if ("contentInBase64".equals(fieldName)) {
contentInBase64 = reader.getString();
contentInBase64 = BinaryData.fromString(reader.getBinary().toString());
contentInBase64Found = true;
} else if ("contentId".equals(fieldName)) {
contentId = reader.getString();
} else {
reader.skipChildren();
}
}
if (nameFound && contentTypeFound && contentInBase64Found) {
return new EmailAttachment(name, contentType, contentInBase64);
EmailAttachment deserializedEmailAttachment = new EmailAttachment(name, contentType, contentInBase64);
deserializedEmailAttachment.contentId = contentId;

return deserializedEmailAttachment;
}
List<String> missingProperties = new ArrayList<>();
if (!nameFound) {
Expand Down
Loading