diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/emails/non-ascii-plain-subject.message | 14 | ||||
-rw-r--r-- | src/gmail.py | 145 | ||||
-rwxr-xr-x | src/send-mail-batch.py | 127 | ||||
-rwxr-xr-x | src/send-mail-strings.py | 58 | ||||
-rwxr-xr-x | src/swaks-batch.sh | 26 |
5 files changed, 247 insertions, 123 deletions
diff --git a/src/emails/non-ascii-plain-subject.message b/src/emails/non-ascii-plain-subject.message new file mode 100644 index 0000000..25c44f4 --- /dev/null +++ b/src/emails/non-ascii-plain-subject.message @@ -0,0 +1,14 @@ +Content-Type: multipart/mixed; boundary="===============1817442041==" +MIME-Version: 1.0 +Subject: Héllò thërê - stored message - ÿȩāḩ +From: {FROM} +To: {TO} + +--===============1817442041== +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit + +Howdy from python! +The subject: Héllò thërê - stored message - ÿȩāḩ +--===============1817442041==-- diff --git a/src/gmail.py b/src/gmail.py new file mode 100644 index 0000000..4e7af04 --- /dev/null +++ b/src/gmail.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import mimetypes +import os +import smtplib + +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_email_string(self, mail, to): + """ + Sends an email from an already created email as a string. + + :param mail: the mail to send + :type mail: str + :param to: a address to send the email. + :type to: str + + :return: an empty dict if everything went ok or + the problems result of sending the email(s). + :rtype: dict + """ + try: + result = self._server.sendmail(self._from, [to], mail) + except Exception as e: + result = {'Exception': repr(e)} + + return result diff --git a/src/send-mail-batch.py b/src/send-mail-batch.py index fceea74..4d889f7 100755 --- a/src/send-mail-batch.py +++ b/src/send-mail-batch.py @@ -1,133 +1,14 @@ #!/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 +from gmail import GMail def send_test_mail(subject): @@ -191,10 +72,10 @@ gmail = GMail(FROM, SECRET) print "Sending {0} mails batch...".format(MAX_MAILS) -count = 1 -while count <= MAX_MAILS: +count = 0 +while count < MAX_MAILS: idx = (count % len(lorem_subjects)) - subject = "[TEST] {0:03} - {1}".format(count, lorem_subjects[idx]) + subject = "[TEST] {0:03} - {1}".format(count+1, lorem_subjects[idx]) print "Sending '{0}' ... ".format(subject), try: problems = send_test_mail(subject) diff --git a/src/send-mail-strings.py b/src/send-mail-strings.py new file mode 100755 index 0000000..b682c90 --- /dev/null +++ b/src/send-mail-strings.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# encoding: utf-8 +# import getpass +import os +import sys + +from ConfigParser import SafeConfigParser + +from gmail import GMail + + +# 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) + +directory = './emails/' +file_list = [] + +for filename in os.listdir(directory): + path = os.path.join(directory, filename) + if os.path.isfile(path): + file_list.append(path) + +print "Sending {0} mail(s)...".format(len(file_list)) + +for mail_file in file_list: + print "Sending '{0}' ... ".format(mail_file), + with open(mail_file) as f: + email = f.read() + + try: + # replace placeholders with actual data + email = email.format(FROM=FROM, TO=','.join(TO)) + except KeyError: + print "Warning: missing placeholder in {0}".format(mail_file) + + try: + problems = gmail.send_email_string(email, TO) + except Exception as e: + problems = repr(e) + + if problems: + print "Problems: {0!r}".format(problems) + else: + print 'ok.' diff --git a/src/swaks-batch.sh b/src/swaks-batch.sh new file mode 100755 index 0000000..1e81210 --- /dev/null +++ b/src/swaks-batch.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# This scripts depends on swaks: http://www.jetmore.org/john/code/swaks/ + +if [ -n "$1" ]; then + SWAKS=$1 +else + SWAKS=swaks +fi + +# if [[ "$SWAKS" == "" ]]; then +if ! `hash $SWAKS 2>/dev/null`; then + echo "Error: I need swaks to work." + echo "You can get swaks from: http://www.jetmore.org/john/code/swaks/" + echo "If you already have it, you can send its location as a first parameter of the script." + echo "E.g.: $0 /path/to/swaks" + exit 1 +fi + +# Customize this in order to test the desired accounts +FROM=ivan@dev.bitmask.net +TO=test_123@dev.bitmask.net + +# NOTE: Add the swak commands below here: + +# Unicode subject and body, without charset specification +$SWAKS --to $TO --from $FROM --header "Subject: Test -- áèīôü" --body "Howdy from swaks. ýëąĥ" --helo 'asdf.com' |