1 | #!/usr/bin/env python
|
---|
2 | #
|
---|
3 | # Rick van der Zwet <rick@vanderzwet.net>
|
---|
4 | #
|
---|
5 | #
|
---|
6 | import argparse
|
---|
7 | import mimetypes
|
---|
8 | import os
|
---|
9 | import random
|
---|
10 | import re
|
---|
11 | import smtplib
|
---|
12 | import socket
|
---|
13 | import string
|
---|
14 | import sys
|
---|
15 | import textwrap
|
---|
16 | import time
|
---|
17 |
|
---|
18 | from time import gmtime,strftime
|
---|
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
|
---|
24 |
|
---|
25 | __svnversion__ = "$Id: foomail.py 405 2020-06-03 11:53:43Z rick $"
|
---|
26 | __author__ = "Rick van der Zwet"
|
---|
27 |
|
---|
28 |
|
---|
29 | default_subject = strftime('Test email send at %a, %d %b %Y %T %z', gmtime())
|
---|
30 |
|
---|
31 | parser = argparse.ArgumentParser(
|
---|
32 | description=textwrap.dedent('''
|
---|
33 | Sent test emails for mailserver verification and debugging
|
---|
34 |
|
---|
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()
|
---|
55 |
|
---|
56 |
|
---|
57 | email = MIMEMultipart()
|
---|
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
|
---|
65 | email['Message-ID' ] = '<' +''.join(random.sample(string.ascii_letters +
|
---|
66 | string.digits,10)) + '@' + email['X-Hostname'] + '>'
|
---|
67 | email['Date'] = strftime('%a, %d %b %Y %T %z',gmtime())
|
---|
68 | email['Subject'] = args.subject
|
---|
69 | email['X-Version'] = __svnversion__
|
---|
70 | email['X-Author'] = __author__
|
---|
71 |
|
---|
72 | tests = []
|
---|
73 | if args.spam:
|
---|
74 | tests.append('spam')
|
---|
75 | if args.virus:
|
---|
76 | test.append('virus')
|
---|
77 | email['X-Tests'] = ' '.join(tests)
|
---|
78 |
|
---|
79 | if args.reply_to:
|
---|
80 | email['Reply-To'] = args.reply_to
|
---|
81 |
|
---|
82 | if args.spam:
|
---|
83 | email['X-Spam'] = 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X'
|
---|
84 |
|
---|
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)
|
---|
102 |
|
---|
103 | for k in list(email.keys()):
|
---|
104 | v = email[k]
|
---|
105 | msg += "* %-15s : %s\n" % (k,v)
|
---|
106 |
|
---|
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 | ''')
|
---|
114 |
|
---|
115 |
|
---|
116 | email.attach(MIMEText(msg))
|
---|
117 |
|
---|
118 | if args.virus:
|
---|
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*')
|
---|
121 | encoders.encode_base64(part)
|
---|
122 | part.add_header('Content-Disposition', 'attachment; filename="eicar.txt"')
|
---|
123 | email.attach(part)
|
---|
124 |
|
---|
125 | if args.file:
|
---|
126 | for filename in args.file:
|
---|
127 | mimetype = mimetypes.guess_type(filename)[0].split('/')
|
---|
128 | part = MIMEBase(mimetype[0],mimetype[1])
|
---|
129 | f = open(filename,'r')
|
---|
130 | part.set_payload(f.read())
|
---|
131 | f.close()
|
---|
132 | encoders.encode_base64(part)
|
---|
133 | part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(filename))
|
---|
134 | email.attach(part)
|
---|
135 |
|
---|
136 | print(email.as_string())
|
---|
137 |
|
---|
138 | if not args.dry_run:
|
---|
139 | mark = time.time()
|
---|
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())
|
---|
145 | server.quit()
|
---|
146 | print("Sending took sec: %.2f" % (time.time() - mark))
|
---|