Last active
April 21, 2020 00:21
-
-
Save SVilgelm/2620a43bfff10376db7d to your computer and use it in GitHub Desktop.
send email
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
from email import header | |
from email.mime import audio | |
from email.mime import application | |
from email.mime import image | |
from email.mime import multipart | |
from email.mime import text | |
import logging | |
import mimetypes | |
import os | |
import re | |
import smtplib | |
import traceback | |
import unittest | |
LOG = logging.getLogger(__name__) | |
RE_EMAIL = re.compile(r'(?P<name>.+)<(?P<email>.+)>') | |
class EmailSender(object): | |
def __init__(self, host='', port=0, user=None, password=None, | |
use_tls=False): | |
self.host = host | |
self.port = port | |
self.user = user | |
self.password = password | |
self.use_tls = use_tls | |
self._smtp = None | |
def __enter__(self): | |
self._smtp = smtplib.SMTP(self.host, self.port) | |
self._smtp.ehlo() | |
if self.use_tls: | |
self._smtp.starttls() | |
self._smtp.ehlo() | |
if self.user is not None and self.password is not None: | |
self._smtp.login(self.user, self.password) | |
return self | |
def __exit__(self, exc_type, exc_val, _exc_tb): | |
if exc_type is not None and exc_val is not None: | |
msg = traceback.format_exception_only(exc_type, exc_val) | |
LOG.error(msg) | |
try: | |
self._smtp.quit() | |
except smtplib.SMTPException as e: | |
LOG.warning(e) | |
self._smtp = None | |
@staticmethod | |
def _files(msg, files): | |
for path in files: | |
ctype, encoding = mimetypes.guess_type(path) | |
if ctype is None or encoding is not None: | |
ctype = 'application/octet-stream' | |
maintype, subtype = ctype.split('/', 1) | |
types = { | |
'text': text.MIMEText, | |
'image': image.MIMEImage, | |
'audio': audio.MIMEAudio | |
} | |
with open(path, 'rb') as f: | |
part = types.get(maintype, application.MIMEApplication)( | |
f.read(), _subtype=subtype) | |
msg.add_header('Content-Disposition', 'attachment', | |
filename=os.path.basename(path)) | |
msg.attach(part) | |
@staticmethod | |
def _body(msg, plain=None, html=None): | |
for body, subtype in ((plain, 'plain'), (html, 'html')): | |
if body: | |
part = text.MIMEText(body, _subtype=subtype, _charset='utf-8') | |
msg.attach(part) | |
@staticmethod | |
def _address(address): | |
m = RE_EMAIL.match(address) | |
if m: | |
address = '%s <%s>' % (header.Header(m.group('name'), 'utf-8'), | |
m.group('email')) | |
return address | |
def send(self, me, to, subject=None, plain=None, html=None, files=None): | |
if self._smtp is None: | |
with self: | |
self.send(me, to, subject, plain, html, files) | |
return | |
if isinstance(to, basestring): | |
to = [to] | |
msg = multipart.MIMEMultipart() | |
msg['From'] = self._address(me) | |
msg['To'] = ', '.join(map(self._address, to)) | |
msg['Subject'] = header.Header(subject or '', 'utf-8') | |
self._body(msg, plain, html) | |
if files is not None: | |
self._files(msg, files) | |
self._smtp.sendmail(me, to, msg.as_string()) | |
__call__ = send | |
class TestEmailSender(unittest.TestCase): | |
def test_init(self): | |
sender = EmailSender() | |
self.assertListEqual(['', 0, None, None, False], | |
[sender.host, sender.port, sender.user, | |
sender.password, sender.use_tls]) | |
if __name__ == '__main__': | |
import argparse | |
import sys | |
parser = argparse.ArgumentParser(conflict_handler='resolve') | |
parser.add_argument('me') | |
parser.add_argument('to', nargs='+') | |
parser.add_argument('-s', '--subject') | |
parser.add_argument('-h', '--host', default='') | |
parser.add_argument('-p', '--port', default=0) | |
parser.add_argument('-u', '--user') | |
parser.add_argument('-w', '--password') | |
parser.add_argument('-u', '--use_tls', action='store_true') | |
parser.add_argument('-f', '--file', action='append') | |
parser.add_argument('-t', '--type', choices=('plain', 'html'), | |
default='plain') | |
args = parser.parse_args() | |
body = sys.stdin.read() | |
plain, html = (body, None) if args.type == 'plain' else (None, body) | |
EmailSender(args.host, args.port, args.user, args.password, args.use_tls)( | |
args.me, args.to, args.subject, plain, html, args.file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment