""" 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