[Python-modules-commits] [python-mailer] 01/02: Imported Upstream version 0.8.1
Hugo Lefeuvre
hle at moszumanska.debian.org
Fri Aug 19 08:51:13 UTC 2016
This is an automated email from the git hooks/post-receive script.
hle pushed a commit to branch master
in repository python-mailer.
commit e2885089f4a3270e8b8fd091f92910de3c539e0b
Author: Hugo Lefeuvre <hle at debian.org>
Date: Fri Aug 19 10:32:41 2016 +0200
Imported Upstream version 0.8.1
---
PKG-INFO | 18 ++
mailer.egg-info/PKG-INFO | 18 ++
mailer.egg-info/SOURCES.txt | 6 +
mailer.egg-info/dependency_links.txt | 1 +
mailer.egg-info/top_level.txt | 1 +
mailer.py | 480 +++++++++++++++++++++++++++++++++++
setup.cfg | 5 +
setup.py | 28 ++
8 files changed, 557 insertions(+)
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..6515890
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,18 @@
+Metadata-Version: 1.1
+Name: mailer
+Version: 0.8.1
+Summary: A module to send email simply in Python
+Home-page: https://bitbucket.org/ginstrom/mailer
+Author: Ryan Ginstrom
+Author-email: ryan at ginstrom.com
+License: MIT License
+Description: UNKNOWN
+Keywords: email,smtp
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
diff --git a/mailer.egg-info/PKG-INFO b/mailer.egg-info/PKG-INFO
new file mode 100644
index 0000000..6515890
--- /dev/null
+++ b/mailer.egg-info/PKG-INFO
@@ -0,0 +1,18 @@
+Metadata-Version: 1.1
+Name: mailer
+Version: 0.8.1
+Summary: A module to send email simply in Python
+Home-page: https://bitbucket.org/ginstrom/mailer
+Author: Ryan Ginstrom
+Author-email: ryan at ginstrom.com
+License: MIT License
+Description: UNKNOWN
+Keywords: email,smtp
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
diff --git a/mailer.egg-info/SOURCES.txt b/mailer.egg-info/SOURCES.txt
new file mode 100644
index 0000000..27a9c7b
--- /dev/null
+++ b/mailer.egg-info/SOURCES.txt
@@ -0,0 +1,6 @@
+mailer.py
+setup.py
+mailer.egg-info/PKG-INFO
+mailer.egg-info/SOURCES.txt
+mailer.egg-info/dependency_links.txt
+mailer.egg-info/top_level.txt
\ No newline at end of file
diff --git a/mailer.egg-info/dependency_links.txt b/mailer.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/mailer.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/mailer.egg-info/top_level.txt b/mailer.egg-info/top_level.txt
new file mode 100644
index 0000000..f2ae723
--- /dev/null
+++ b/mailer.egg-info/top_level.txt
@@ -0,0 +1 @@
+mailer
diff --git a/mailer.py b/mailer.py
new file mode 100644
index 0000000..1aa8e94
--- /dev/null
+++ b/mailer.py
@@ -0,0 +1,480 @@
+#coding: UTF8
+"""
+mailer module
+
+Simple front end to the smtplib and email modules,
+to simplify sending email.
+
+A lot of this code was taken from the online examples in the
+email module documentation:
+http://docs.python.org/library/email-examples.html
+
+Released under MIT license.
+
+Version 0.5 is based on a patch by Douglas Mayle
+
+Sample code:
+
+ import mailer
+
+ message = mailer.Message()
+ message.From = "me at example.com"
+ message.To = "you at example.com"
+ message.RTo = "you at example.com"
+ message.Subject = "My Vacation"
+ message.Body = open("letter.txt", "rb").read()
+ message.attach("picture.jpg")
+
+ sender = mailer.Mailer('mail.example.com')
+ sender.send(message)
+
+"""
+from __future__ import with_statement
+import smtplib
+import socket
+import threading
+import Queue
+import uuid
+
+# this is to support name changes
+# from version 2.4 to version 2.5
+try:
+ from email import encoders
+ from email.header import make_header
+ from email.mime.audio import MIMEAudio
+ from email.mime.base import MIMEBase
+ from email.mime.image import MIMEImage
+ from email.mime.multipart import MIMEMultipart
+ from email.mime.text import MIMEText
+except ImportError:
+ from email import Encoders as encoders
+ from email.Header import make_header
+ from email.MIMEAudio import MIMEAudio
+ from email.MIMEBase import MIMEBase
+ from email.MIMEImage import MIMEImage
+ from email.MIMEMultipart import MIMEMultipart
+ from email.MIMEText import MIMEText
+
+# For guessing MIME type based on file name extension
+import mimetypes
+import time
+
+from os import path
+
+__version__ = "0.8.1"
+__author__ = "Ryan Ginstrom"
+__license__ = "MIT"
+__description__ = "A module to send email simply in Python"
+
+
+class Mailer(object):
+ """
+ Represents an SMTP connection.
+
+ Use login() to log in with a username and password.
+ """
+
+ def __init__(self, host="localhost", port=0, use_tls=False, usr=None, pwd=None, use_ssl=False, use_plain_auth=False,
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
+ self.host = host
+ self.port = port
+ self.use_tls = use_tls
+ self.use_ssl = use_ssl
+ self.use_plain_auth = use_plain_auth
+ self._usr = usr
+ self._pwd = pwd
+ self.timeout = timeout
+
+ def login(self, usr, pwd):
+ self._usr = usr
+ self._pwd = pwd
+
+ def send(self, msg, debug=False):
+ """
+ Send one message or a sequence of messages.
+
+ Every time you call send, the mailer creates a new
+ connection, so if you have several emails to send, pass
+ them as a list:
+ mailer.send([msg1, msg2, msg3])
+ """
+ if self.use_ssl:
+ server = smtplib.SMTP_SSL(self.host, self.port, timeout=self.timeout)
+ else:
+ server = smtplib.SMTP(self.host, self.port, timeout=self.timeout)
+
+ if debug:
+ server.set_debuglevel(1)
+
+ if self._usr and self._pwd:
+ if self.use_tls is True:
+ server.ehlo()
+ server.starttls()
+ server.ehlo()
+
+ if self.use_plain_auth is True:
+ server.esmtp_features["auth"] = "LOGIN PLAIN"
+
+ server.login(self._usr, self._pwd)
+
+ if isinstance(msg, Message):
+ msg = [msg]
+
+ for m in msg:
+ self._send(server, m)
+
+ server.quit()
+
+ def _send(self, server, msg):
+ """
+ Sends a single message using the server
+ we created in send()
+ """
+ me = msg.From
+ if isinstance(msg.To, basestring):
+ to = [msg.To]
+ else:
+ to = list(msg.To)
+
+ cc = []
+ if msg.CC:
+ if isinstance(msg.CC, basestring):
+ cc = [msg.CC]
+ else:
+ cc = list(msg.CC)
+
+ bcc = []
+ if msg.BCC:
+ if isinstance(msg.BCC, basestring):
+ bcc = [msg.BCC]
+ else:
+ bcc = list(msg.BCC)
+
+ rto = []
+ if msg.RTo:
+ if isinstance(msg.RTo, basestring):
+ rto = [msg.RTo]
+ else:
+ rto = list(msg.RTo)
+
+ you = to + cc + bcc
+ server.sendmail(me, you, msg.as_string())
+
+
+class Message(object):
+ """
+ Represents an email message.
+
+ Set the To, From, Reply-To, Subject, and Body attributes as plain-text strings.
+ Optionally, set the Html attribute to send an HTML email, or use the
+ attach() method to attach files.
+
+ Use the charset property to send messages using other than us-ascii
+
+ If you specify an attachments argument, it should be a list of
+ attachment filenames: ["file1.txt", "file2.txt"]
+
+ `To` should be a string for a single address, and a sequence
+ of strings for multiple recipients (castable to list)
+
+ Send using the Mailer class.
+ """
+
+ def __init__(self, **kwargs):
+ """
+ Parameters and default values (parameter names are case insensitive):
+ To=None, From=None, RTo=None, CC=None, BCC=None, Subject=None, Body=None, Html=None,
+ Date=None, Attachments=None, Charset=None, Headers=None
+ """
+
+ # extract parameters and convert names to lowercase
+ params = {}
+ for i in kwargs:
+ params[i.lower()] = kwargs[i]
+
+ # preprocess attachments
+ self.attachments = []
+ attachments = params.get('attachments', None)
+ if attachments:
+ for attachment in attachments:
+ if isinstance(attachment, basestring):
+ self.attachments.append((attachment, None, None, None, None))
+ else:
+ try:
+ length = len(attachment)
+ except TypeError:
+ length = None
+ else:
+ if length is None or length <= 4:
+ self.attachments.append((attachment, None, None, None, None))
+ else:
+ self.attachments.append((tuple(attachment) + (None, None, None, None))[:4])
+
+
+ self.To = params.get('to', None)
+ self.RTo = params.get('rto', None)
+ self.CC = params.get('cc', None)
+ self.BCC = params.get('bcc', None)
+ self.From = params.get('from', None) # string or iterable
+ self.Subject = params.get('subject', u'') # string
+ self.Body = params.get('body', None)
+ self.Html = params.get('html', None)
+ self.Date = params.get('date', time.strftime("%a, %d %b %Y %H:%M:%S %z", time.gmtime()))
+ self.charset = params.get('charset', 'us-ascii')
+ self.Headers = params.get('headers', {})
+
+ if isinstance(self.Body, unicode):
+ self.Body = self.Body.encode(self.charset)
+
+ self.message_id = self.make_key()
+
+
+ def make_key(self):
+ return str(uuid.uuid4())
+
+ def header(self, key, value):
+ self.Headers[key] = value
+
+ def as_string(self):
+ """Get the email as a string to send in the mailer"""
+
+ if not self.attachments:
+ return self._plaintext()
+ else:
+ return self._multipart()
+
+ def _plaintext(self):
+ """Plain text email with no attachments"""
+
+ if not self.Html:
+ msg = MIMEText(self.Body, 'plain', self.charset)
+ else:
+ msg = self._with_html()
+
+ self._set_info(msg)
+ return msg.as_string()
+
+ def _with_html(self):
+ """There's an html part"""
+
+ outer = MIMEMultipart('alternative')
+
+ part1 = MIMEText(self.Body, 'plain', self.charset)
+ part2 = MIMEText(self.Html, 'html', self.charset)
+
+ outer.attach(part1)
+ outer.attach(part2)
+
+ return outer
+
+ def _set_info(self, msg):
+ if self.charset == 'us-ascii':
+ msg['Subject'] = self.Subject
+ msg['From'] = self.From
+
+ else:
+ if isinstance(self.Subject, unicode):
+ subject = self.Subject
+ else:
+ subject = unicode(self.Subject, self.charset)
+ msg['Subject'] = str(make_header([(subject, self.charset)]))
+
+ if isinstance(self.From, unicode):
+ from_ = self.From
+ else:
+ from_ = unicode(self.From, self.charset)
+ msg['From'] = str(make_header([(from_, self.charset)]))
+
+
+ if isinstance(self.To, basestring):
+ msg['To'] = self.To
+ else:
+ self.To = list(self.To)
+ msg['To'] = ", ".join(self.To)
+
+ if self.RTo:
+ if isinstance(self.RTo, basestring):
+ msg.add_header('reply-to', self.RTo)
+ else:
+ self.RTo = list(self.RTo)
+ msg.add_header('reply-to', ", ".join(self.RTo))
+
+ if self.CC:
+ if isinstance(self.CC, basestring):
+ msg['CC'] = self.CC
+ else:
+ self.CC = list(self.CC)
+ msg['CC'] = ", ".join(self.CC)
+
+
+ if self.BCC:
+ if isinstance(self.BCC, basestring):
+ msg['BCC'] = self.BCC
+ else:
+ self.BCC = list(self.BCC)
+ msg['BCC'] = ", ".join(self.BCC)
+
+
+ if self.Headers:
+ for key, value in self.Headers.items():
+ msg[key] = str(value).encode(self.charset)
+
+
+ msg['Date'] = self.Date
+
+ def _multipart(self):
+ """The email has attachments"""
+
+ msg = MIMEMultipart('related')
+
+ if self.Html:
+ outer = MIMEMultipart('alternative')
+
+ part1 = MIMEText(self.Body, 'plain', self.charset)
+ part1.add_header('Content-Disposition', 'inline')
+
+ part2 = MIMEText(self.Html, 'html', self.charset)
+ part2.add_header('Content-Disposition', 'inline')
+
+ outer.attach(part1)
+ outer.attach(part2)
+ msg.attach(outer)
+ else:
+ msg.attach(MIMEText(self.Body, 'plain', self.charset))
+
+ self._set_info(msg)
+ msg.preamble = self.Subject
+
+ for filename, cid, mimetype, content, charset in self.attachments:
+ self._add_attachment(msg, filename, cid, mimetype, content, charset)
+
+ return msg.as_string()
+
+ def _add_attachment(self, outer, filename, cid, mimetype, content, charset):
+ """
+ If mimetype is None, it will try to guess the mimetype
+ """
+ if mimetype:
+ ctype = mimetype
+ encoding = None
+ else:
+ ctype, encoding = mimetypes.guess_type(filename)
+
+ if ctype is None or encoding is not None:
+ # No guess could be made, or the file is encoded (compressed), so
+ # use a generic bag-of-bits type.
+ ctype = 'application/octet-stream'
+
+ maintype, subtype = ctype.split('/', 1)
+ if not content:
+ with open(filename, 'rb') as fp:
+ content = fp.read()
+
+ if maintype == 'text':
+ # Note: we should handle calculating the charset
+ msg = MIMEText(content, _subtype=subtype, _charset=charset)
+ elif maintype == 'image':
+ msg = MIMEImage(content, _subtype=subtype)
+ elif maintype == 'audio':
+ msg = MIMEAudio(content, _subtype=subtype)
+ else:
+ msg = MIMEBase(maintype, subtype)
+ msg.set_payload(content)
+ # Encode the payload using Base64
+ encoders.encode_base64(msg)
+
+ # Set the content-ID header
+ if cid:
+ msg.add_header('Content-ID', '<%s>' % cid)
+ msg.add_header('Content-Disposition', 'inline')
+ else:
+ # Set the filename parameter
+ msg.add_header('Content-Disposition', 'attachment', filename=path.basename(filename))
+
+ outer.attach(msg)
+
+ def attach(self, filename, cid=None, mimetype=None, content=None, charset=None):
+ """
+ Attach a file to the email. Specify the name of the file;
+ Message will figure out the MIME type and load the file.
+
+ Specify mimetype to set the MIME type manually. The content
+ argument take the contents of the file if they are already loaded
+ in memory.
+ """
+
+ self.attachments.append((filename, cid, mimetype, content, charset))
+
+
+class Manager(threading.Thread):
+ """
+ Manages the sending of email in the background.
+
+ You can supply it with an instance of class Mailer or pass in the same
+ parameters that you would have used to create an instance of Mailer.
+
+ If a message was succesfully sent, self.results[msg.message_id] returns a 3
+ element tuple (True/False, err_code, err_message).
+ """
+
+ def __init__(self, mailer=None, callback=None, **kwargs):
+ threading.Thread.__init__(self)
+
+ self.queue = Queue.Queue()
+ self.mailer = mailer
+ self.abort = False
+ self.callback = callback
+ self._results = {}
+ self._result_lock = threading.RLock()
+
+ if self.mailer is None:
+ self.mailer = Mailer(
+ host=kwargs.get('host', 'localhost'),
+ port=kwargs.get('port', 25),
+ use_tls=kwargs.get('use_tls', False),
+ usr=kwargs.get('usr', None),
+ pwd=kwargs.get('pwd', None),
+ )
+
+ def __getattr__(self, name):
+ if name == 'results':
+ with self._result_lock:
+ return self._results
+ else:
+ return None
+
+ def run(self):
+
+ while self.abort is False:
+ msg = self.queue.get(block=True)
+ if msg is None:
+ break
+
+ if isinstance(msg, Message):
+ msg = [msg]
+
+ for m in msg:
+ try:
+ self.results[m.message_id] = (False, -1, '')
+ self.mailer.send(m)
+ self.results[m.message_id] = (True, 0, '')
+
+ except Exception as e:
+ args = e.args
+ if len(args) < 2:
+ args = (-1, e.args[0])
+
+ self.results[m.message_id] = (False, args[0], args[1])
+
+ if self.callback:
+ try:
+ self.callback(m.message_id)
+ except Exception:
+ pass
+
+ # endfor
+
+ self.queue.task_done()
+
+ def send(self, msg):
+ self.queue.put(msg)
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..b14b0bc
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..60030cd
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,28 @@
+from setuptools import setup
+import sys
+
+extra = {}
+if sys.version_info >= (3, 0):
+ extra.update(use_2to3=True)
+
+setup(
+ name='mailer',
+ version="0.8.1",
+ description="A module to send email simply in Python",
+ author="Ryan Ginstrom",
+ author_email='ryan at ginstrom.com',
+ url="https://bitbucket.org/ginstrom/mailer",
+ py_modules=["mailer"],
+ keywords=["email", "smtp"],
+ license="MIT License",
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'License :: OSI Approved :: MIT License',
+ "Operating System :: MacOS :: MacOS X",
+ "Operating System :: Microsoft :: Windows",
+ "Operating System :: POSIX",
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ ],
+ **extra
+)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-mailer.git
More information about the Python-modules-commits
mailing list