From c2193e770b9401fe49e7b703ac83a17491b083b5 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 10 Jan 2014 15:44:47 -0300 Subject: Add script to send a mail batch --- .gitignore | 3 + src/lorem-ipsum-subjects.txt | 50 +++++++++++ src/options.cfg.demo | 11 +++ src/send-mail-batch.py | 209 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 273 insertions(+) create mode 100644 src/lorem-ipsum-subjects.txt create mode 100644 src/options.cfg.demo create mode 100755 src/send-mail-batch.py diff --git a/.gitignore b/.gitignore index ded6067..fc5764f 100644 --- a/.gitignore +++ b/.gitignore @@ -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 index 0000000..5d98233 --- /dev/null +++ b/src/lorem-ipsum-subjects.txt @@ -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 index 0000000..8f2c5ba --- /dev/null +++ b/src/options.cfg.demo @@ -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 index 0000000..fceea74 --- /dev/null +++ b/src/send-mail-batch.py @@ -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 -- cgit v1.2.3