1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
"""
Demonstrate sending mail via SMTP while employing TLS and performing
authentication.
"""
import sys
from twisted.internet import reactor
from twisted.internet.defer import Deferred
from twisted.internet.ssl import optionsForClientTLS
from twisted.mail.smtp import ESMTPSenderFactory
from twisted.python.usage import Options, UsageError
def sendmail(
authenticationUsername,
authenticationSecret,
fromAddress,
toAddress,
messageFile,
smtpHost,
smtpPort=25,
):
"""
@param authenticationUsername: The username with which to authenticate.
@param authenticationSecret: The password with which to authenticate.
@param fromAddress: The SMTP reverse path (ie, MAIL FROM)
@param toAddress: The SMTP forward path (ie, RCPT TO)
@param messageFile: A file-like object containing the headers and body of
the message to send.
@param smtpHost: The MX host to which to connect.
@param smtpPort: The port number to which to connect.
@return: A Deferred which will be called back when the message has been
sent or which will errback if it cannot be sent.
"""
# Create a TLS context factory.
contextFactory = optionsForClientTLS(smtpHost.decode("utf8"))
resultDeferred = Deferred()
senderFactory = ESMTPSenderFactory(
authenticationUsername,
authenticationSecret,
fromAddress,
toAddress,
messageFile,
resultDeferred,
contextFactory=contextFactory,
)
reactor.connectTCP(smtpHost, smtpPort, senderFactory)
return resultDeferred
class SendmailOptions(Options):
synopsis = "smtpclient_tls.py [options]"
optParameters = [
(
"username",
"u",
None,
"The username with which to authenticate to the SMTP server.",
),
(
"password",
"p",
None,
"The password with which to authenticate to the SMTP server.",
),
("from-address", "f", None, "The address from which to send the message."),
("to-address", "t", None, "The address to which to send the message."),
("message", "m", None, "The filename which contains the message to send."),
("smtp-host", "h", None, "The host through which to send the message."),
("smtp-port", None, "25", "The port number on smtp-host to which to connect."),
]
def postOptions(self):
"""
Parse integer parameters, open the message file, and make sure all
required parameters have been specified.
"""
try:
self["smtp-port"] = int(self["smtp-port"])
except ValueError:
raise UsageError("--smtp-port argument must be an integer.")
if self["username"] is None:
raise UsageError("Must specify authentication username with --username")
if self["password"] is None:
raise UsageError("Must specify authentication password with --password")
if self["from-address"] is None:
raise UsageError("Must specify from address with --from-address")
if self["to-address"] is None:
raise UsageError("Must specify from address with --to-address")
if self["smtp-host"] is None:
raise UsageError("Must specify smtp host with --smtp-host")
if self["message"] is None:
raise UsageError("Must specify a message file to send with --message")
try:
self["message"] = open(self["message"])
except Exception as e:
raise UsageError(e)
def cbSentMessage(result):
"""
Called when the message has been sent.
Report success to the user and then stop the reactor.
"""
print("Message sent")
reactor.stop()
def ebSentMessage(err):
"""
Called if the message cannot be sent.
Report the failure to the user and then stop the reactor.
"""
err.printTraceback()
reactor.stop()
def main(args=None):
"""
Parse arguments and send an email based on them.
"""
o = SendmailOptions()
try:
o.parseOptions(args)
except UsageError as e:
raise SystemExit(e)
else:
from twisted.python import log
log.startLogging(sys.stdout)
result = sendmail(
o["username"],
o["password"],
o["from-address"],
o["to-address"],
o["message"],
o["smtp-host"],
o["smtp-port"],
)
result.addCallbacks(cbSentMessage, ebSentMessage)
reactor.run()
if __name__ == "__main__":
main(sys.argv[1:])
|