90 lines
3.7 KiB
Python
90 lines
3.7 KiB
Python
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
|
# https://stackoverflow.com/questions/5239797/python-smtplib-proxy-support
|
|
# https://stackoverflow.com/questions/19642726/testing-python-smtp-email-service
|
|
import socket
|
|
import smtplib
|
|
|
|
import socks
|
|
|
|
class ProxySMTP(smtplib.SMTP):
|
|
def __init__(self, host='', port=0, local_hostname=None,
|
|
timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
|
|
source_address=None, proxy_addr=None, proxy_port=None):
|
|
"""Initialize a new instance.
|
|
|
|
If specified, `host' is the name of the remote host to which to
|
|
connect. If specified, `port' specifies the port to which to connect.
|
|
By default, smtplib.SMTP_PORT is used. If a host is specified the
|
|
connect method is called, and if it returns anything other than a
|
|
success code an SMTPConnectError is raised. If specified,
|
|
`local_hostname` is used as the FQDN of the local host in the HELO/EHLO
|
|
command. Otherwise, the local hostname is found using
|
|
socket.getfqdn(). The `source_address` parameter takes a 2-tuple (host,
|
|
port) for the socket to bind to as its source address before
|
|
connecting. If the host is '' and port is 0, the OS default behavior
|
|
will be used.
|
|
|
|
"""
|
|
self._host = host
|
|
self.timeout = timeout
|
|
self.esmtp_features = {}
|
|
self.command_encoding = 'ascii'
|
|
self.source_address = source_address
|
|
self.proxy_addr = proxy_addr
|
|
self.proxy_port = proxy_port
|
|
|
|
if host:
|
|
(code, msg) = self.connect(host, port)
|
|
if code != 220:
|
|
self.close()
|
|
raise smtplib.SMTPConnectError(code, msg)
|
|
if local_hostname is not None:
|
|
self.local_hostname = local_hostname
|
|
else:
|
|
# RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and
|
|
# if that can't be calculated, that we should use a domain literal
|
|
# instead (essentially an encoded IP address like [A.B.C.D]).
|
|
fqdn = socket.getfqdn()
|
|
if '.' in fqdn:
|
|
self.local_hostname = fqdn
|
|
else:
|
|
# We can't find an fqdn hostname, so use a domain literal
|
|
addr = '127.0.0.1'
|
|
try:
|
|
addr = socket.gethostbyname(socket.gethostname())
|
|
except socket.gaierror:
|
|
pass
|
|
self.local_hostname = '[%s]' % addr
|
|
|
|
def _get_socket(self, host, port, timeout):
|
|
# This makes it simpler for SMTP_SSL to use the SMTP connect code
|
|
# and just alter the socket connection bit.
|
|
if self.debuglevel > 0:
|
|
self._print_debug('connect: to', (host, port), self.source_address)
|
|
return socks.create_connection((host, port),
|
|
proxy_type=socks.PROXY_TYPE_SOCKS5,
|
|
timeout=timeout,
|
|
proxy_addr=self.proxy_addr,
|
|
proxy_port=self.proxy_port)
|
|
|
|
# And to use:
|
|
|
|
if __name__ == '__main__':
|
|
user_email, user_pass = 'foo', 'bar'
|
|
email_server = ProxySMTP('smtp.gmail.com', 587,
|
|
proxy_addr='127.0.0.1',
|
|
proxy_port=9050,
|
|
timeout=20)
|
|
email_server.starttls()
|
|
try:
|
|
email_server.login(user_email, user_pass)
|
|
except smtplib.SMTPAuthenticationError as e:
|
|
if len(e.args) > 1:
|
|
code = e.args[0]
|
|
if code = 535:
|
|
# 5.7.8 Username and Password not accepted
|
|
pass
|
|
raise
|
|
email_server.sendmail(user_email, recipient_list, msg.as_string())
|
|
email_server.quit()
|