Add script to send a mail batch
authorIvan Alejandro <ivanalejandro0@gmail.com>
Fri, 10 Jan 2014 18:44:47 +0000 (15:44 -0300)
committerIvan Alejandro <ivanalejandro0@gmail.com>
Mon, 13 Jan 2014 19:18:11 +0000 (16:18 -0300)
.gitignore
src/lorem-ipsum-subjects.txt [new file with mode: 0644]
src/options.cfg.demo [new file with mode: 0644]
src/send-mail-batch.py [new file with mode: 0755]

index ded6067..fc5764f 100644 (file)
@@ -34,3 +34,6 @@ nosetests.xml
 .mr.developer.cfg
 .project
 .pydevproject
+
+# Ignore file containing sensitive data
+options.cfg
diff --git a/src/lorem-ipsum-subjects.txt b/src/lorem-ipsum-subjects.txt
new file mode 100644 (file)
index 0000000..5d98233
--- /dev/null
@@ -0,0 +1,50 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit
+Ullamcorper Maecenas orci duis malesuada
+Condimentum imperdiet quam nascetur vestibulum
+Venenatis elit fusce platea facilisi
+Et Cubilia phasellus pharetra dictum
+Vivamus ultricies viverra habitasse faucibus
+Eleifend eros Et ac urna
+Dui mauris senectus lorem malesuada
+Metus sed Lorem fames nullam
+Parturient conubia tempor suscipit netus
+Inceptos cum lorem risus congue
+Dui tempor ultrices nisl lectus
+Justo ullamcorper risus gravida sit
+Velit primis Quis est sagittis
+Eros dignissim litora id suscipit
+Senectus Eros aptent mollis cubilia
+Vitae ultricies Habitasse purus praesent
+Magnis mauris vitae facilisi dictum
+Condimentum velit gravida a nullam
+Non at magna consectetur congue
+Dolor id ipsum duis vehicula
+Taciti cum augue dictumst morbi
+Habitant magnis vitae amet porta
+Libero turpis fusce eros ut
+Non eu lorem commodo duis
+Parturient proin Mattis placerat congue
+Magnis elementum iaculis litora cras
+Scelerisque felis nostra pellentesque nisi
+Parturient conubia himenaeos varius ultrices
+Rutrum cursus Nostra dictumst aliquam
+Quam blandit pharetra cras purus
+Arcu viverra Amet magna pharetra
+Felis aenean lobortis ridiculus molestie
+Venenatis scelerisque accumsan varius vehicula
+Inceptos dui proin gravida diam
+Per euismod in facilisis id
+Turpis feugiat lacus viverra aliquam
+Metus rutrum Lobortis interdum sem
+Dolor dui primis interdum suscipit
+Adipiscing lacinia mollis phasellus fames
+Habitant laoreet faucibus suspendisse hendrerit
+Parturient lacus phasellus suscipit mus
+Justo iaculis Bibendum ridiculus mattis
+Hac justo Habitant nec diam
+Eu enim conubia proin leo
+Metus scelerisque nec magna pulvinar
+Dolor felis porta cubilia mus
+Felis vitae vulputate adipiscing tincidunt
+Dis odio vivamus erat torquent
+Habitant arcu vivamus vehicula sit
diff --git a/src/options.cfg.demo b/src/options.cfg.demo
new file mode 100644 (file)
index 0000000..8f2c5ba
--- /dev/null
@@ -0,0 +1,11 @@
+# You need to copy this file to 'options.cfg' and update it
+# using your preferences.
+# 'options.cfg' is ignored by git.
+
+[Credentials]
+account = your.test.account@gmail.com
+password = password placeholder
+
+[Configs]
+mails_amount = 10
+to = test_account@bitmask.net
diff --git a/src/send-mail-batch.py b/src/send-mail-batch.py
new file mode 100755 (executable)
index 0000000..fceea74
--- /dev/null
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# import getpass
+import mimetypes
+import os
+import sys
+import random
+import smtplib
+import time
+
+from ConfigParser import SafeConfigParser
+
+from email import encoders
+from email.mime.base import MIMEBase
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+
+
+class GMail(object):
+    """Email sender using the gmail service."""
+    SMTPSERVER = 'smtp.gmail.com:587'
+
+    def __init__(self, account, password):
+        """
+        Initializes the class.
+        You should provide credentials in order to login into gmail.
+
+        :param account: the username@gmail.com account to use for sending.
+        :type account: str
+        :param password: the password for the account.
+        :type password: str
+        """
+        self._from = account
+        login = account.split('@')[0]
+        self._server = smtplib.SMTP(self.SMTPSERVER)
+        self._server.starttls()
+        self._server.login(login, password)
+
+    def __del__(self):
+        """
+        Quits the server.
+        """
+        self._server.quit()
+
+    def _get_attachment(self, file_path):
+        """
+        Creates the MIMEBase attachment for the file 'file_path'.
+
+        Might raise:
+            IOError
+
+        :param file_path: the file from to generate the attachment from.
+        :type file_path: str
+
+        :return: the MIMEBase attachment.
+        :rtype: MIMEBase
+        """
+        ctype, encoding = mimetypes.guess_type(file_path)
+        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)
+
+        # Read the file, this may rise IOError
+        with open(file_path, 'rb') as fp:
+            the_file = MIMEBase(maintype, subtype)
+            the_file.set_payload(fp.read())
+
+        # Encode the payload using Base64
+        encoders.encode_base64(the_file)
+
+        # Set the filename parameter
+        the_file.add_header('Content-Disposition', 'attachment',
+                            filename=os.path.basename(file_path))
+
+        return the_file
+
+    def send_email(self, to_addr_list, cc_addr_list, subject,
+                   message, attachments=None):
+        """
+        Sends an email.
+
+        :param to_addr_list: a list of addresses to send the email.
+        :type to_addr_list: list of str
+        :param cc_addr_list: a list of addresses to send (as CC) the email.
+        :type cc_addr_list: list of str
+        :param subject: the subject of the email
+        :type subject: str
+        :param message: the message to send
+        :type message: str
+        :param attachments: a list of paths for the files to attach.
+        :type attachments: list of str
+
+        :return: an empty dict if everything went ok or
+                 the problems result of sending the email(s).
+        :rtype: dict
+        """
+        # Create the container (outer) email message.
+        msg = MIMEMultipart()
+        msg['Subject'] = subject
+        msg['From'] = self._from
+        msg['To'] = ', '.join(to_addr_list)
+
+        if cc_addr_list:
+            msg['Cc'] = ', '.join(cc_addr_list)
+
+        # Add the message's text
+        msg.attach(MIMEText(message))
+
+        problems = ''
+        if attachments is not None:
+            # Attach every file in the attachment parameter
+            for file_path in attachments:
+                try:
+                    the_file = self._get_attachment(file_path)
+                    msg.attach(the_file)
+                except IOError:
+                    problems += "Could not attach {0!r}\n".format(file_path)
+
+        message = msg.as_string()
+        try:
+            result = self._server.sendmail(self._from, to_addr_list, message)
+        except Exception as e:
+            result['Exception'] = repr(e)
+
+        if problems:
+            result['Attachments'] = problems
+
+        return result
+
+
+def send_test_mail(subject):
+    # make a list of attachments, add all the files in 'directory'
+    directory = './attachments/'
+    file_list = []
+
+    # randomize the use of attachments
+    if random.choice([True, False]):
+        for filename in os.listdir(directory):
+            path = os.path.join(directory, filename)
+            if os.path.isfile(path):
+                file_list.append(path)
+
+        # randomize attachments
+        ammount = random.randint(0, len(file_list)-1)
+        random.shuffle(file_list)
+        file_list = file_list[0:ammount]
+
+    msg = ('Howdy from python!\n'
+           'The subject: {0}\n'
+           "Current date & time: {1}\n"
+           "Trying to attach: {2!r}"
+           ).format(subject, time.strftime("%c"), file_list)
+
+    return gmail.send_email(
+        to_addr_list=TO, cc_addr_list=[],
+        subject=subject, message=msg, attachments=file_list)
+
+# Read subjects from file
+lorem_subjects = []
+lorem_file = './lorem-ipsum-subjects.txt'
+with open(lorem_file) as lorem:
+    lorem_subjects = [line.strip() for line in lorem]
+
+
+# Mail account to send from:
+# use this if you want to enter manually your password:
+# FROM = 'your.username@gmail.com'
+# SECRET = getpass.getpass("Password for {0}: ".format(FROM))
+
+# MAX_MAILS = 10
+# TO = ['test_account@dev.bitmask.net']
+
+# Read credentials from options file
+parser = SafeConfigParser()
+parser.read('options.cfg')
+try:
+    FROM = parser.get('Credentials', 'account')
+    SECRET = parser.get('Credentials', 'password')
+    TO = [parser.get('Configs', 'to')]
+    MAX_MAILS = parser.getint('Configs', 'mails_amount')
+except Exception as e:
+    print "Problem reading options.cfg"
+    print "Exception: {0!r}".format(e)
+    sys.exit()
+
+
+# create the GMail global object
+gmail = GMail(FROM, SECRET)
+
+print "Sending {0} mails batch...".format(MAX_MAILS)
+
+count = 1
+while count <= MAX_MAILS:
+    idx = (count % len(lorem_subjects))
+    subject = "[TEST] {0:03} - {1}".format(count, lorem_subjects[idx])
+    print "Sending '{0}' ... ".format(subject),
+    try:
+        problems = send_test_mail(subject)
+    except Exception as e:
+        problems = repr(e)
+
+    if problems:
+        print "Problems: {0!r}".format(problems)
+    else:
+        print 'ok.'
+
+    count += 1