# -*- 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()