[2] | 1 | #!/usr/bin/env python
|
---|
| 2 | #
|
---|
[405] | 3 | # Rick van der Zwet <rick@vanderzwet.net>
|
---|
[2] | 4 | #
|
---|
[405] | 5 | #
|
---|
| 6 | import argparse
|
---|
[2] | 7 | import mimetypes
|
---|
[405] | 8 | import os
|
---|
| 9 | import random
|
---|
| 10 | import re
|
---|
| 11 | import smtplib
|
---|
| 12 | import socket
|
---|
| 13 | import string
|
---|
| 14 | import sys
|
---|
| 15 | import textwrap
|
---|
[2] | 16 | import time
|
---|
[405] | 17 |
|
---|
[2] | 18 | from time import gmtime,strftime
|
---|
[404] | 19 | from email.mime.multipart import MIMEMultipart
|
---|
| 20 | from email.mime.base import MIMEBase
|
---|
| 21 | from email.mime.text import MIMEText
|
---|
| 22 | from email.utils import COMMASPACE, formatdate
|
---|
| 23 | from email import encoders
|
---|
[2] | 24 |
|
---|
[405] | 25 | __svnversion__ = "$Id: foomail.py 405 2020-06-03 11:53:43Z rick $"
|
---|
[2] | 26 | __author__ = "Rick van der Zwet"
|
---|
| 27 |
|
---|
| 28 |
|
---|
[405] | 29 | default_subject = strftime('Test email send at %a, %d %b %Y %T %z', gmtime())
|
---|
[2] | 30 |
|
---|
[405] | 31 | parser = argparse.ArgumentParser(
|
---|
| 32 | description=textwrap.dedent('''
|
---|
| 33 | Sent test emails for mailserver verification and debugging
|
---|
[2] | 34 |
|
---|
[405] | 35 | Author : %s
|
---|
| 36 | Version: %s
|
---|
| 37 | ''' % (__author__, __svnversion__)),
|
---|
| 38 | formatter_class=argparse.RawDescriptionHelpFormatter)
|
---|
| 39 | parser.add_argument('--from', '-f', dest='sender', required=True)
|
---|
| 40 | parser.add_argument('--recipient', '-r', required=True)
|
---|
| 41 | parser.add_argument('--server', '-s', required=True)
|
---|
| 42 | parser.add_argument('--cc', help='Carbon Copy header')
|
---|
| 43 | parser.add_argument('--file', action='append', help='Attachments to sent')
|
---|
| 44 | parser.add_argument('--hostname', default=socket.gethostname(), help='EHLO/HELO hostname to present')
|
---|
| 45 | parser.add_argument('--message', help='Alternative message text of body')
|
---|
| 46 | parser.add_argument('--subject', default=default_subject, help='Alternative Subject header')
|
---|
| 47 | parser.add_argument('--spam', action='store_true', help='Include X-Spam testing headers')
|
---|
| 48 | parser.add_argument('--port', type=int, default=25, help='SMTP port used for connection')
|
---|
| 49 | parser.add_argument('--reply-to', help='Set Reply-To: header')
|
---|
| 50 | parser.add_argument('--to', help='Alternative To: header')
|
---|
| 51 | parser.add_argument('--silent', action='store_true', help='Do not-follow SMTP flow verbosely')
|
---|
| 52 | parser.add_argument('--virus', action='store_true', help='Include eicar.txt sample virus')
|
---|
| 53 | parser.add_argument('--dry-run', '-d', action='store_true', help='Do not actually sent out the message')
|
---|
| 54 | args = parser.parse_args()
|
---|
[2] | 55 |
|
---|
| 56 |
|
---|
| 57 | email = MIMEMultipart()
|
---|
[405] | 58 | email['From'] = 'Testing sender <' + args.sender + '>'
|
---|
| 59 | email['To'] = args.to or args.recipient
|
---|
| 60 | if args.cc:
|
---|
| 61 | email['Cc'] = args.cc
|
---|
| 62 | email['X-Server'] = args.server
|
---|
| 63 | email['X-Port'] = str(args.port)
|
---|
| 64 | email['X-Hostname'] = args.hostname
|
---|
[404] | 65 | email['Message-ID' ] = '<' +''.join(random.sample(string.ascii_letters +
|
---|
[2] | 66 | string.digits,10)) + '@' + email['X-Hostname'] + '>'
|
---|
| 67 | email['Date'] = strftime('%a, %d %b %Y %T %z',gmtime())
|
---|
[405] | 68 | email['Subject'] = args.subject
|
---|
[2] | 69 | email['X-Version'] = __svnversion__
|
---|
| 70 | email['X-Author'] = __author__
|
---|
| 71 |
|
---|
[405] | 72 | tests = []
|
---|
| 73 | if args.spam:
|
---|
| 74 | tests.append('spam')
|
---|
| 75 | if args.virus:
|
---|
| 76 | test.append('virus')
|
---|
| 77 | email['X-Tests'] = ' '.join(tests)
|
---|
[2] | 78 |
|
---|
[405] | 79 | if args.reply_to:
|
---|
| 80 | email['Reply-To'] = args.reply_to
|
---|
[2] | 81 |
|
---|
[405] | 82 | if args.spam:
|
---|
| 83 | email['X-Spam'] = 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X'
|
---|
[2] | 84 |
|
---|
[405] | 85 | if args.message:
|
---|
| 86 | f = open(args.message,'r')
|
---|
| 87 | msg = f.read()
|
---|
| 88 | f.close()
|
---|
| 89 | else:
|
---|
| 90 | msg = textwrap.dedent('''
|
---|
| 91 | Hi,
|
---|
| 92 |
|
---|
| 93 | Sorry to bother you...
|
---|
| 94 |
|
---|
| 95 | Please ignore this message as it is used to test
|
---|
| 96 | and verify systems to make sure everything works
|
---|
| 97 | flawless.
|
---|
| 98 |
|
---|
| 99 | %(virus)s
|
---|
| 100 |
|
---|
| 101 | Technical details:\n''' % email)
|
---|
[2] | 102 |
|
---|
[404] | 103 | for k in list(email.keys()):
|
---|
[2] | 104 | v = email[k]
|
---|
| 105 | msg += "* %-15s : %s\n" % (k,v)
|
---|
| 106 |
|
---|
[405] | 107 | msg += textwrap.dedent('''
|
---|
| 108 | Best regards,
|
---|
| 109 | Your system administrator
|
---|
| 110 | --
|
---|
| 111 | BSD Licensed Source Code for this tool at:
|
---|
| 112 | https://rickvanderzwet.nl/svn/personal/foomailer
|
---|
| 113 | ''')
|
---|
[2] | 114 |
|
---|
| 115 |
|
---|
| 116 | email.attach(MIMEText(msg))
|
---|
| 117 |
|
---|
[405] | 118 | if args.virus:
|
---|
[2] | 119 | part = MIMEBase('application', "octet-stream")
|
---|
| 120 | part.set_payload('X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*')
|
---|
[404] | 121 | encoders.encode_base64(part)
|
---|
[2] | 122 | part.add_header('Content-Disposition', 'attachment; filename="eicar.txt"')
|
---|
| 123 | email.attach(part)
|
---|
| 124 |
|
---|
[405] | 125 | if args.file:
|
---|
| 126 | for filename in args.file:
|
---|
| 127 | mimetype = mimetypes.guess_type(filename)[0].split('/')
|
---|
[2] | 128 | part = MIMEBase(mimetype[0],mimetype[1])
|
---|
[405] | 129 | f = open(filename,'r')
|
---|
[2] | 130 | part.set_payload(f.read())
|
---|
| 131 | f.close()
|
---|
[404] | 132 | encoders.encode_base64(part)
|
---|
[405] | 133 | part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(filename))
|
---|
[2] | 134 | email.attach(part)
|
---|
| 135 |
|
---|
[404] | 136 | print(email.as_string())
|
---|
[2] | 137 |
|
---|
[405] | 138 | if not args.dry_run:
|
---|
[2] | 139 | mark = time.time()
|
---|
[405] | 140 | server = smtplib.SMTP(args.server, args.port, timeout=600)
|
---|
| 141 | server.set_debuglevel(not args.silent)
|
---|
| 142 | server.helo(args.hostname)
|
---|
| 143 | server.ehlo(args.hostname)
|
---|
| 144 | server.sendmail(args.sender, args.recipient, email.as_string())
|
---|
[2] | 145 | server.quit()
|
---|
[404] | 146 | print("Sending took sec: %.2f" % (time.time() - mark))
|
---|