"""
This module contains a function to send a newsletter from HTML content.
???+ warning "Pre-requisites"
To use this module, the following variables must be defined in your .env file:
`smtpHost`, `smtpPort`, `smtpKey`, `smtpSecret`
See the [.env file configuration][configure-your-env-file] section if needed
To use this module in your script, import the module like so.
```
from djagitit.mailing import smtp
```
"""
import smtplib
from email.message import EmailMessage
from email.headerregistry import Address
import os
from itertools import zip_longest
from dotenv import load_dotenv
load_dotenv()
def _safely_getenv(var):
"""Checks if environment variable is defined before returning it"""
if not os.getenv(var):
raise EnvironmentError(f'Environment variable {var} not defined!')
return os.getenv(var)
def _attach_file(email, file_path):
with open(file_path, 'rb') as file:
email.add_attachment(
file.read(),
maintype='application',
subtype='octet-stream',
filename=os.path.basename(file_path)
)
return email
def send_newsletter(subject, html, sender, to=None, cc=None, bcc=None, sender_alias=None, reply_to=None, attachments=None):
"""
Sends a newsletter email from HTML content to a list of recipients.
Args:
subject (str): The subject of the newsletter email.
html (str): The HTML content of the newsletter email.
sender (str): The email address of the sender.
to (list or str, optional): A list of email addresses or a single email address of the recipients. If omitted, defaults to sender email.
cc (list or str, optional): A list of email addresses or a single email address of the cc recipients.
bcc (list or str, optional): A list of email addresses or a single email address of the bcc recipients.
sender_alias (str, optional): An optional alias for the sender's name.
reply_to (str, optional): An optional email address to set as the reply-to address.
attachments (list or str, optional): Optional paths of files to add as attachments.
Returns:
r (dict): The response from the smtp server. Empty if no issue occured. Contains the issue message otherwise.
Example:
```
subject = 'The Infamous Newsletter'
html = '
Check it out now!
'
sender = 'julien.comte@sonymusic.com'
to = ['julien.comte@sonymusic.com','matti.karjalainen@sonymusic.com']
cc = 'alikutay.bengi@sonymusic.com'
sender_alias = 'CEA Data Team'
reply_to = 'julien.comte@sonymusic.com'
attachments = ['path/to/a/cool/spreadsheet.xlsx', 'path/to/another/nice/file.txt']
smtp.send_newsletter(subject, html, sender, diffusion_list, sender_alias, reply_to, attachments)
```
"""
# load smtp credentials
smtp_server = _safely_getenv('smtpHost')
smtp_port = _safely_getenv('smtpPort')
username = _safely_getenv('smtpKey')
password = _safely_getenv('smtpSecret')
email = EmailMessage()
email['Subject'] = subject
if sender_alias:
email['From'] = Address(display_name=sender_alias, addr_spec=sender)
else:
email['From'] = sender
if reply_to:
email['Reply-To'] = reply_to
# If recipients not defined, send to yourself
if not to:
to = [sender]
# if recipients is a single email address, convert it to a list
if not isinstance(to, list):
to = [to]
if cc and not isinstance(cc, list):
cc = [cc]
if bcc and not isinstance(bcc, list):
bcc = [bcc]
# if attachment path is a string, convert it to a list
if attachments and not isinstance(attachments, list):
attachments = [attachments]
email.set_content('This is a plain text body.')
email.add_alternative(html, subtype = 'html')
if attachments:
for a in attachments:
email = _attach_file(email, a)
max_recipients = 49
to_lists = [to[i:i+max_recipients] for i in range(0, len(to), max_recipients)]
cc_lists = [cc[i:i+max_recipients] for i in range(0, len(cc), max_recipients)] if cc else [None]
bcc_lists = [bcc[i:i+max_recipients] for i in range(0, len(bcc), max_recipients)] if bcc else [None]
for t, c, b in zip_longest(to_lists, cc_lists, bcc_lists):
email['To'] = to
if c:
email['Cc'] = c
if b:
email['Bcc'] = b
try:
with smtplib.SMTP(host=smtp_server, port=smtp_port,) as server:
server.starttls()
server.login(username, password)
r = server.send_message(email)
server.quit()
except smtplib.SMTPResponseException as e:
error_code = e.smtp_code
error_message = e.smtp_error
r = {error_code: error_message}
print(f'{error_code}: {error_message}')
return r