Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions src/communication/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/communication/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 "[email protected]" --subject "Contoso Update" --to "[email protected]" "[email protected]" --text "Hello valued client. There is an update."
```
##### Get-Email-Status #####
```
az communication email status get --message-id "01234567-89ab-cdef-0123-012345678901"
```
12 changes: 12 additions & 0 deletions src/communication/azext_communication/manual/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
28 changes: 28 additions & 0 deletions src/communication/azext_communication/manual/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 "[email protected]" --subject "Contoso Update" --to "[email protected]" "[email protected]" --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"
"""
32 changes: 32 additions & 0 deletions src/communication/azext_communication/manual/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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):
Expand Down Expand Up @@ -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')
12 changes: 12 additions & 0 deletions src/communication/azext_communication/manual/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, _):
Expand All @@ -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):
Expand Down Expand Up @@ -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)
87 changes: 87 additions & 0 deletions src/communication/azext_communication/manual/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
2 changes: 1 addition & 1 deletion src/communication/azext_communication/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------


VERSION = '1.4.1'
VERSION = '1.5.0'


def cli_application_id():
Expand Down
1 change: 1 addition & 0 deletions src/communication/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'azure-communication-sms',
'azure-communication-chat',
'azure-communication-rooms',
'azure-communication-email >= 1.0.0b1',
]

try:
Expand Down