From fe52b570b679cf999f085d8c3ba05a94608403fe Mon Sep 17 00:00:00 2001 From: Mayssam <105318860+mayssamm@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:47:36 -0800 Subject: [PATCH] [Communication] Email commands in preview mode (#5825) * [Communication] update communication module version to 1.4.1, remove redundant version in setup * [Communication] add email command group in preview mode * fix typo in email status get parameter setup * Add more help for email commands. --- src/communication/HISTORY.rst | 5 ++ src/communication/README.md | 8 ++ .../manual/_client_factory.py | 12 +++ .../azext_communication/manual/_help.py | 28 ++++++ .../azext_communication/manual/_params.py | 32 +++++++ .../azext_communication/manual/commands.py | 12 +++ .../azext_communication/manual/custom.py | 87 +++++++++++++++++++ .../azext_communication/version.py | 2 +- src/communication/setup.py | 1 + 9 files changed, 186 insertions(+), 1 deletion(-) diff --git a/src/communication/HISTORY.rst b/src/communication/HISTORY.rst index be4478084e5..2834c299b2f 100644 --- a/src/communication/HISTORY.rst +++ b/src/communication/HISTORY.rst @@ -3,6 +3,11 @@ Release History =============== +1.5.0 +++++++ + * Add communication email command group in preview mode + + 1.4.1 ++++++ * Update version missed in previous release diff --git a/src/communication/README.md b/src/communication/README.md index 6566255259c..84e7ab91c4d 100644 --- a/src/communication/README.md +++ b/src/communication/README.md @@ -178,3 +178,11 @@ az communication rooms participant update --room "roomId" --presenter-participan ``` az communication rooms participant remove --room "roomId" --participants "8:acs:xxxxxx" "8:acs:xxxxxx" "8:acs:xxxxxx" "8:acs:xxxxxx" ``` +##### Send-Email ##### +``` +az communication email send --sender "NoReply@contoso.com" --subject "Contoso Update" --to "user1@user1-domain.com" "user2@user2-domain.com" --text "Hello valued client. There is an update." +``` +##### Get-Email-Status ##### +``` +az communication email status get --message-id "01234567-89ab-cdef-0123-012345678901" +``` diff --git a/src/communication/azext_communication/manual/_client_factory.py b/src/communication/azext_communication/manual/_client_factory.py index 49b873e6de8..72d24735ffe 100644 --- a/src/communication/azext_communication/manual/_client_factory.py +++ b/src/communication/azext_communication/manual/_client_factory.py @@ -78,3 +78,15 @@ def cf_communication_rooms(cli_ctx, kwargs): client = RoomsClient.from_connection_string(connection_string) return client + + +def cf_communication_email(cli_ctx, kwargs): + from azure.communication.email import EmailClient + + connection_string = kwargs.pop('connection_string', None) + if connection_string is None: + error_msg = 'Please specify --connection-string, or set AZURE_COMMUNICATION_CONNECTION_STRING.' + raise RequiredArgumentMissingError(error_msg) + + client = EmailClient.from_connection_string(connection_string) + return client diff --git a/src/communication/azext_communication/manual/_help.py b/src/communication/azext_communication/manual/_help.py index 947d984b82b..ea70452da9b 100644 --- a/src/communication/azext_communication/manual/_help.py +++ b/src/communication/azext_communication/manual/_help.py @@ -504,3 +504,31 @@ text: |- az communication rooms participant remove --room "12345678901234567" --participants "8:acs:xxxxxx" "8:acs:xxxxxx" "8:acs:xxxxxx" """ + +helps['communication email'] = """ + type: group + short-summary: Commands to send emails and get the status of emails previously sent using Azure Communication Services Email service. +""" + +helps['communication email status'] = """ + type: group + short-summary: Commands to get the status of emails previously sent using Azure Communication Services Email service. +""" + +helps['communication email send'] = """ + type: command + short-summary: "Send an email." + examples: + - name: Send an email from an existing domain + text: |- + az communication email send --sender "NoReply@contoso.com" --subject "Contoso Update" --to "user1@user1-domain.com" "user2@user2-domain.com" --text "Hello valued client. There is an update." +""" + +helps['communication email status get'] = """ + type: command + short-summary: "Get status of an email previously sent." + examples: + - name: Get status of an email + text: |- + az communication email status get --message-id "01234567-89ab-cdef-0123-012345678901" +""" diff --git a/src/communication/azext_communication/manual/_params.py b/src/communication/azext_communication/manual/_params.py index e8286701c24..01f43fc2e24 100644 --- a/src/communication/azext_communication/manual/_params.py +++ b/src/communication/azext_communication/manual/_params.py @@ -3,6 +3,8 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +from azure.cli.core.commands.parameters import get_enum_type, get_three_state_flag + def load_arguments(self, _): with self.argument_context('communication update') as c: @@ -13,6 +15,7 @@ def load_arguments(self, _): _load_phonenumber_arguments(self) _load_chat_arguments(self) _load_rooms_arguments(self) + _load_email_arguments(self) def _load_identity_arguments(self): @@ -242,3 +245,32 @@ def _load_rooms_arguments(self): type=str, help='Room Id') c.argument('participants', options_list=['--participants'], nargs='+', help='Collection of identities that will be removed from the room.') + + +def _load_email_arguments(self): + with self.argument_context('communication email send') as c: + c.argument('sender', options_list=['--sender'], type=str, help='Sender email address from a verified domain.') + c.argument('subject', options_list=['--subject'], type=str, help='Subject of the email message.') + c.argument('text', options_list=['--text'], type=str, help='Plain text version of the email message. Optional.') + c.argument('html', options_list=['--html'], type=str, help='Html version of the email message. Optional.') + c.argument('importance', options_list=['--importance'], arg_type=get_enum_type(['normal', 'low', 'high']), + help='The importance type for the email. Known values are: high,' + ' normal, and low. Default is normal. Optional') + c.argument('recipients_to', options_list=['--to'], nargs='+', help='Recepients email addresses.') + c.argument('recipients_cc', options_list=['--cc'], nargs='+', help='Carbon copy email addresses.') + c.argument('recipients_bcc', options_list=['--bcc'], nargs='+', help='Blind carbon copy email addresses.') + c.argument('reply_to', options_list=['--reply-to'], type=str, help='Reply-to email address. Optional.') + c.argument('disable_tracking', options_list=['--disable-tracking'], arg_type=get_three_state_flag(), + help='Indicates whether user engagement tracking should be disabled for this request if' + 'the resource-level user engagement tracking setting was already enabled. Optional.') + c.argument('attachments', options_list=['--attachments'], nargs='+', + help='List of email attachments. Optional.') + c.argument('attachment_types', options_list=['--attachment-types'], nargs='+', + help='List of email attachment types, in the same order of attachments.' + ' Required for each attachment. Known values are: avi, bmp, doc, docm,' + ' docx, gif, jpeg, mp3, one, pdf, png, ppsm, ppsx, ppt, pptm, pptx,' + ' pub, rpmsg, rtf, tif, txt, vsd, wav, wma, xls, xlsb, xlsm, and xlsx') + + with self.argument_context('communication email status get') as c: + c.argument('message_id', options_list=['--message-id'], type=str, + help='System generated message id (GUID) returned from a previous call to send email') diff --git a/src/communication/azext_communication/manual/commands.py b/src/communication/azext_communication/manual/commands.py index c2ae1d74c0b..098f21b45e7 100644 --- a/src/communication/azext_communication/manual/commands.py +++ b/src/communication/azext_communication/manual/commands.py @@ -9,6 +9,7 @@ from azext_communication.manual._client_factory import cf_communication_phonenumbers from azext_communication.manual._client_factory import cf_communication_chat from azext_communication.manual._client_factory import cf_communication_rooms +from azext_communication.manual._client_factory import cf_communication_email def load_command_table(self, _): @@ -17,6 +18,7 @@ def load_command_table(self, _): _load_phonenumber_command_table(self) _load_chat_command_table(self) _load_rooms_command_table(self) + _load_email_command_table(self) def _load_identity_command_table(self): @@ -102,3 +104,13 @@ def _load_rooms_command_table(self): g.communication_custom_command('add', 'communication_rooms_add_participants', rooms_arguments) g.communication_custom_command('update', 'communication_rooms_update_participants', rooms_arguments) g.communication_custom_command('remove', 'communication_rooms_remove_participants', rooms_arguments, confirmation=True) + + +def _load_email_command_table(self): + rooms_arguments = ['connection_string'] + self.command_group('communication email', is_preview=True) + + with self.command_group('communication email', client_factory=cf_communication_email, is_preview=True) as g: + g.communication_custom_command('send', 'communication_email_send', rooms_arguments) + with self.command_group('communication email', client_factory=cf_communication_email, is_preview=True) as g: + g.communication_custom_command('status get', 'communication_email_get_status', rooms_arguments) diff --git a/src/communication/azext_communication/manual/custom.py b/src/communication/azext_communication/manual/custom.py index 97b0eb794b9..cbbce5e2eef 100644 --- a/src/communication/azext_communication/manual/custom.py +++ b/src/communication/azext_communication/manual/custom.py @@ -293,3 +293,90 @@ def communication_rooms_remove_participants(client, room_id, participants): raise except Exception as ex: sys.exit(str(ex)) + + +def __get_attachment_content(filename, filetype): + import base64 + import os + from azure.communication.email import EmailAttachment + + _, tail = os.path.split(filename) + with open(filename, "r", encoding="utf-8") as file: + file_content = file.read() + + base64_content = base64.b64encode(bytes(file_content, 'utf-8')) + + return EmailAttachment( + name=tail, + attachment_type=filetype, + content_bytes_base64=base64_content.decode(), + ) + + +def communication_email_send(client, + subject, + sender, + recipients_to, + disable_tracking=False, + text=None, + html=None, + importance='normal', + recipients_cc=None, + recipients_bcc=None, + reply_to=None, + attachments=None, + attachment_types=None): + + from azure.communication.email import EmailContent, EmailAddress, EmailMessage, EmailRecipients + from knack.util import CLIError + + try: + email_content = EmailContent( + subject=subject, + plain_text=text, + html=html, + ) + + to_address = [EmailAddress(email=r) for r in recipients_to] + + reply_to_address = None if reply_to is None else [EmailAddress(email=reply_to)] + + if attachments is None and attachment_types is None: + attachments_list = None + elif attachments is None or attachment_types is None: + raise CLIError('Number of attachments and attachment-types should match.') + elif len(attachments) != len(attachment_types): + raise CLIError('Number of attachments and attachment-types should match.') + else: + attachments_list = [ + __get_attachment_content(attachments[i], attachment_types[i]) + for i in range(len(attachments)) + ] + + message = EmailMessage( + sender=sender, + content=email_content, + recipients=EmailRecipients( + to=to_address, + cc=[] if recipients_cc is None else [EmailAddress(email=r) for r in recipients_cc], + bcc=[] if recipients_bcc is None else [EmailAddress(email=r) for r in recipients_bcc]), + importance=importance, + reply_to=reply_to_address, + disable_user_engagement_tracking=disable_tracking, + attachments=attachments_list, + ) + + return client.send(message) + except HttpResponseError: + raise + except Exception as ex: + sys.exit(str(ex)) + + +def communication_email_get_status(client, message_id): + try: + return client.get_send_status(message_id) + except HttpResponseError: + raise + except Exception as ex: + sys.exit(str(ex)) diff --git a/src/communication/azext_communication/version.py b/src/communication/azext_communication/version.py index 1aca1eb313f..6095a817d78 100644 --- a/src/communication/azext_communication/version.py +++ b/src/communication/azext_communication/version.py @@ -4,7 +4,7 @@ # -------------------------------------------------------------------------------------------- -VERSION = '1.4.1' +VERSION = '1.5.0' def cli_application_id(): diff --git a/src/communication/setup.py b/src/communication/setup.py index 8aacfaf082f..c9125a03679 100644 --- a/src/communication/setup.py +++ b/src/communication/setup.py @@ -34,6 +34,7 @@ 'azure-communication-sms', 'azure-communication-chat', 'azure-communication-rooms', + 'azure-communication-email >= 1.0.0b1', ] try: