diff --git a/layercake/layercake/email_.py b/layercake/layercake/email_.py index a625c98..19e467c 100644 --- a/layercake/layercake/email_.py +++ b/layercake/layercake/email_.py @@ -1,29 +1,41 @@ from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -from email.utils import formataddr +from email.utils import formataddr as formataddr_ from pathlib import Path +type Email = str +type NamedEmail = tuple[str, Email] +type Address = Email | list[Email] | NamedEmail | list[NamedEmail] + class Message: def __init__( self, - from_: tuple[str | None, str], - to: tuple[str | None, str], + from_: NamedEmail, + to: Address, subject: str, - reply_to: tuple[str | None, str] | None = None, + cc: Address | None = None, + bcc: Address | None = None, + reply_to: NamedEmail | None = None, content: str | None = None, ) -> None: self._references = set() self._body = MIMEMultipart('alternative') self._message = MIMEMultipart('mixed') - self._message['From'] = formataddr(from_) + self._message['From'] = formataddr_(from_) self._message['To'] = formataddr(to) self._message['Subject'] = subject self._message.attach(self._body) if reply_to: - self._message['Reply-To'] = formataddr(reply_to) + self._message['Reply-To'] = formataddr_(reply_to) + + if cc: + self._message['Cc'] = formataddr(cc) + + if bcc: + self._message['Bcc'] = formataddr(bcc) if content: self.add_alternative(content, subtype='plain') @@ -62,3 +74,13 @@ class Message: self._message['References'] = ' '.join(self._references) return self._message.as_bytes() + + +def formataddr(address: Address) -> str: + if isinstance(address, str): + return formataddr_((None, address)) + + if isinstance(address, tuple): + return formataddr_(address) + + return ', '.join([formataddr(addr) for addr in address]) diff --git a/layercake/pyproject.toml b/layercake/pyproject.toml index 31d982b..93b2608 100644 --- a/layercake/pyproject.toml +++ b/layercake/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "layercake" -version = "0.8.0" +version = "0.8.1" description = "Packages shared dependencies to optimize deployment and ensure consistency across functions." readme = "README.md" authors = [ diff --git a/layercake/tests/test_email.py b/layercake/tests/test_email.py index 25af883..fd524be 100644 --- a/layercake/tests/test_email.py +++ b/layercake/tests/test_email.py @@ -4,7 +4,7 @@ from pathlib import Path import boto3 import pytest from layercake.dateutils import now -from layercake.email_ import Message +from layercake.email_ import Message, formataddr from moto import mock_aws @@ -18,31 +18,65 @@ def aws_credentials(): os.environ['AWS_DEFAULT_REGION'] = 'sa-east-1' -def test_send_email(aws_credentials): - from_ = 'pytest@eduseg.com.br' +def test_formataddr(): + assert ( + formataddr(('Sérgio', 'sergio@somosbeta.com.br')) + == '=?utf-8?q?S=C3=A9rgio?= ' + ) + + assert formataddr('sergio@somosbeta.com.br') == 'sergio@somosbeta.com.br' + + assert ( + formataddr( + [ + ('Sérgio', 'sergio@somosbeta.com.br'), + ('Tiago', 'tiago@somosbeta.com.br'), + ] + ) + == '=?utf-8?q?S=C3=A9rgio?= , Tiago ' + ) + + +def test_send_email(): + from_ = ('EDUSEG®', 'pytest@eduseg.com.br') + to = [ + ('Sérgio', 'sergio+pytest1@somosbeta.com.br'), + ('Sergio', 'sergio+pytest2@somosbeta.com.br'), + ] + emailmsg = Message( + to=to, + from_=from_, + bcc='osergiosiqueira@gmail.com', + subject='áéíóúnõ', + reply_to=('', 'osergiosiqueira@gmail.com'), + content='Lorem ipsum dolor sit amet, consectetur adipiscing elit', + ) + emailmsg.add_header('X-Feedback', f'uid=123; oid=123; date={now().isoformat()}') + emailmsg.add_alternative( + """ +

áéíóúnõ

+ html + """ + ) + emailmsg.attach(Path('tests/samples/test.pdf'), 'relatório.pdf') with mock_aws(): ses = boto3.client('ses', region_name='sa-east-1') - ses.verify_email_identity(EmailAddress=from_) - to = ('Sérgio', 'sergio@somosbeta.com.br') - msg = Message( - to=to, - from_=('Beta Educação', from_), - subject='áéíóúnõ', - reply_to=('', 'osergiosiqueira@gmail.com'), - content='Lorem ipsum dolor sit amet, consectetur adipiscing elit', - ) - msg.add_header('X-Feedback', f'uid=123; oid=123; date={now().isoformat()}') - msg.add_alternative( - """ -

áéíóúnõ

- html - """ - ) - msg.attach(Path('tests/samples/test.pdf'), 'relatório.pdf') + ses.verify_email_identity(EmailAddress=from_[1]) assert ses.send_raw_email( - Source=from_, - Destinations=[to[1]], - RawMessage={'Data': msg.as_bytes()}, + Source=from_[1], + Destinations=[to[0][1]], + RawMessage={'Data': emailmsg.as_bytes()}, ) + + # sesv2 = boto3.client('sesv2') + # r = sesv2.send_email( + # Content={ + # 'Raw': { + # 'Data': emailmsg.as_bytes(), + # }, + # } + # ) + + # assert 'MessageId' in r