From f01d442cfa47d02e0397a26a1da2255e2e233f67 Mon Sep 17 00:00:00 2001 From: Alex Kerney Date: Thu, 28 Sep 2017 07:45:32 -0400 Subject: [PATCH] Something more like a real initial commit --- README.rst | 69 +++++++++++++++++++++++++- email_to/__init__.py | 2 + email_to/email_to.py | 112 +++++++++++++++++++++++++++++++++++++++++++ setup.py | 0 4 files changed, 182 insertions(+), 1 deletion(-) mode change 100644 => 100755 setup.py diff --git a/README.rst b/README.rst index 1d09745..5f74db6 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,74 @@ Simplyify sending HTML emails Features -------- -* TODO +The built in Python modules for sending email are powerful, but require a lot of +boilerplate to write an HTML formatted email. + +.. code-block:: python + + from email.mime.multipart import MIMEMultipart + from email.mime.text import MIMEText + import smtplib + + message = MIMEMultipart('alternative') + message['Subject'] = 'Test' + message['From'] = 'user@gmail.com' + message['To'] = 'someone@else.com' + + message.attach(MIMEText('# A Heading\nSomething else in the body', 'plain') + message.attach(MIMEText('

A Heading

Something else in the body

', 'html') + + server = smtplib.SMTP('smtp.gmail.com', 587) + server.starttls() + server.login('user@gmail.com', 'password') + server.sendmail('user@gmail.com', 'someone@else.com', message.as_string()) + server.quit() + +With ``email_to`` sending a simple email becomes much more succint. + +.. code-block:: python + + import email_to + + server = email_to.EmailServer('smtp.gmail.com', 587, 'user@gmail.com', 'password') + server.quick_email('someone@else.com', 'Test', + ['# A Heading', 'Something else in the body'], + style='h1 {color: blue}') + + +``email_to`` also supports building a message up, line by line. This is +especially useful for monitoring scripts where there may be several different +conditions of interest. + +.. code-block:: python + + import email_to + + server = email_to.EmailServer('smtp.gmail.com', 587, 'user@gmail.com', 'password') + + message = server.message() + message.add('# Oh boy, something went wrong!') + message.add('- The server had a hiccup') + message.add('- The power went out') + message.add('- Blame it on a rogue backhoe') + message.style = 'h1 { color: red}' + + message.send('someone@else.com', 'Things did not occur as expected') + +Additionally if the server details are not known at the beginning of the message, +that can be handled easily too. + +.. code-block:: python + + import email_to + + message = email_to.Message('# Every thing is ok') + message.add('Everything has been running fine for days.') + message.add('Probably time to build something new and break everything') + message.style = 'h1 { color: green }' + + server = email_to.EmailServer('smtp.gmail.com', 587, 'user@gmail.com', 'password') + server.send_message(message, 'someone@else.com', 'Things are awesome') Credits --------- diff --git a/email_to/__init__.py b/email_to/__init__.py index e0b8b05..3206d16 100644 --- a/email_to/__init__.py +++ b/email_to/__init__.py @@ -2,6 +2,8 @@ """Top-level package for Email To.""" +from email_to.email_to import EmailServer, Message + __author__ = """Alex Kerney""" __email__ = 'abk@mac.com' __version__ = '0.1.0' diff --git a/email_to/email_to.py b/email_to/email_to.py index 7fbbae4..633454f 100644 --- a/email_to/email_to.py +++ b/email_to/email_to.py @@ -1,3 +1,115 @@ # -*- coding: utf-8 -*- """Main module.""" + +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +import smtplib + +import markdown +import premailer + + +class Message(object): + """ A simple email message made of Markdown strings + + A Message is a simplified version of a MIMEMultipart email message. + Instead of having to seperately construct HTML and text version of + an email, you can build a Message by adding lines of Markdown formatted + strings. + + """ + def __init__(self, body=None, style=None, server=None): + """ + Args: + body (str, bytes, iterable of strings): The body of the email. + It does not need to be complete, as you can add to it later. + style (str): CSS formatting to be applied to HTML formatted verion + of email. + server (EmailServer): An EmailServer instance allowing a message + to be sent directly from it's `send` method. + + """ + if body is None: + self.body = [] + else: + if any((isinstance(body, str), isinstance(body, bytes))): + body = [body] + self.body = body + self.style = style + self.server = server + + def add(self, line): + """ Adds a new Markdown formatted line to the current email body """ + self.body.append(line) + + @property + def html(self): + """ Returns HTML formatted and styled version of body """ + html = markdown.markdown('\n'.join(self.body)) + if self.style: + return premailer.transform('\n' + html) + return html + + def __str__(self): + return '\n'.join(self.body) + + def __repr__(self): + return ''.format( + self.body[0], (len(self.body) - 1)) + + def mime(self): + """ Returns a MIMEMultipart message """ + msg = MIMEMultipart('alternative') + + msg.attach(MIMEText(str(self), 'plain')) + msg.attach(MIMEText(self.html, 'html')) + + return msg + + def send(self, to, subject): + """ Sends the formatted message to given recripient + + args: + to (:obj:str, iterable of :obj:`str`): Email addresses to send to + subject (str): Subject line of email to send + + """ + self.server.send_message(self, to, subject) + + +class EmailServer(object): + def __init__(self, url, port, email, password): + self.url = url + self.port = port + self.email_address = email + self.password = password + + def _login(self): + self.server = smtplib.SMTP(self.url, self.port) + self.server.starttls() + self.server.login(self.email_address, self.password) + + def _logout(self): + self.server.quit() + + def quick_email(self, to, subject, body, style=None): + message = Message(body, style=style) + + self.send_message(message, to, subject) + + def send_message(self, message, to, subject): + message = message.mime() + + message['From'] = self.email_address + message['To'] = to + + message['Subject'] = subject + + self._login() + self.server.sendmail(self.email_address, to, message.as_string()) + self._logout() + + def message(self, body=None, style=None): + return Message(body=body, style=style, server=self) diff --git a/setup.py b/setup.py old mode 100644 new mode 100755