Python es compatible con el proxy smtplib

Me gustaría enviar un correo electrónico a través de un proxy.

Mi implementación actual es la siguiente:

Me conecto al servidor smtp con autenticación. Después de haber iniciado sesión correctamente, le envío un correo electrónico. Funciona bien, pero cuando veo el encabezado del correo electrónico puedo ver el nombre de mi host. Me gustaría hacer un túnel a través de un proxy en su lugar.

Cualquier ayuda será muy apreciada.

Use SocksiPy :

import smtplib import socks #'proxy_port' should be an integer #'PROXY_TYPE_SOCKS4' can be replaced to HTTP or PROXY_TYPE_SOCKS5 socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS4, proxy_host, proxy_port) socks.wrapmodule(smtplib) smtp = smtplib.SMTP() ... 

Ayer tuve un problema similar, este es el código que escribí para resolver el problema. Invisiblemente le permite utilizar todos los métodos smtp a través de proxy.

 #!/usr/bin/env python # -*- coding: utf-8 -*- # # smtprox.py # Shouts to suidrewt # # ############################################# # # This module allows Proxy support in MailFux. # # Shouts to Betrayed for telling me about # # http CONNECT # # ############################################# # import smtplib import socket def recvline(sock): stop = 0 line = '' while True: i = sock.recv(1) if i == '\n': stop = 1 line += i if stop == 1: break return line class ProxSMTP( smtplib.SMTP ): def __init__(self, host='', port=0, p_address='',p_port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): """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. An SMTPConnectError is raised if the specified `host' doesn't respond correctly. If specified, `local_hostname` is used as the FQDN of the local host. By default, the local hostname is found using socket.getfqdn(). """ self.p_address = p_address self.p_port = p_port self.timeout = timeout self.esmtp_features = {} self.default_port = smtplib.SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: raise 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 [ABCD]). 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 smtplib.SMTP.__init__(self) def _get_socket(self, port, host, 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: print>>stderr, 'connect:', (host, port) new_socket = socket.create_connection((self.p_address,self.p_port), timeout) new_socket.sendall("CONNECT {0}:{1} HTTP/1.1\r\n\r\n".format(port,host)) for x in xrange(2): recvline(new_socket) return new_socket 

Este código ha ganado de mí. 1. El nombre del archivo no debe ser email.py Cambie el nombre del archivo, por ejemplo, emailSend.py 2. Es necesario permitir que Google envíe mensajes de fonts no confiables.

El módulo smtplib no incluye la funcionalidad para conectarse a un servidor SMTP a través de un proxy HTTP. La clase personalizada publicada por ryoh no funcionó para mí, aparentemente porque mi proxy HTTP solo recibe mensajes codificados. Escribí la siguiente clase personalizada basada en el código de Ryos, y está funcionando bien.

 import smtplib import socket def recvline(sock): """Receives a line.""" stop = 0 line = '' while True: i = sock.recv(1) if i.decode('UTF-8') == '\n': stop = 1 line += i.decode('UTF-8') if stop == 1: print('Stop reached.') break print('Received line: %s' % line) return line class ProxySMTP(smtplib.SMTP): """Connects to a SMTP server through a HTTP proxy.""" def __init__(self, host='', port=0, p_address='',p_port=0, local_hostname=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): """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. An SMTPConnectError is raised if the specified `host' doesn't respond correctly. If specified, `local_hostname` is used as the FQDN of the local host. By default, the local hostname is found using socket.getfqdn(). """ self.p_address = p_address self.p_port = p_port self.timeout = timeout self.esmtp_features = {} self.default_port = smtplib.SMTP_PORT if host: (code, msg) = self.connect(host, port) if code != 220: raise IOError(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 [ABCD]). 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 smtplib.SMTP.__init__(self) def _get_socket(self, port, host, timeout): # This makes it simpler for SMTP to use the SMTP connect code # and just alter the socket connection bit. print('Will connect to:', (host, port)) print('Connect to proxy.') new_socket = socket.create_connection((self.p_address,self.p_port), timeout) s = "CONNECT %s:%s HTTP/1.1\r\n\r\n" % (port,host) s = s.encode('UTF-8') new_socket.sendall(s) print('Sent CONNECT. Receiving lines.') for x in range(2): recvline(new_socket) print('Connected.') return new_socket 

Para conectarse al servidor SMTP, solo use la clase ProxySMTP lugar de smtplib.SMTP .

 proxy_host = YOUR_PROXY_HOST proxy_port = YOUR_PROXY_PORT # Both port 25 and 587 work for SMTP conn = ProxySMTP(host='smtp.gmail.com', port=587, p_address=proxy_host, p_port=proxy_port) conn.ehlo() conn.starttls() conn.ehlo() r, d = conn.login(YOUR_EMAIL_ADDRESS, YOUR_PASSWORD) print('Login reply: %s' % r) sender = 'from@fromdomain.com' receivers = ['to@todomain.com'] message = """From: From Person  To: To Person  Subject: SMTP e-mail test This is a test e-mail message. """ print('Send email.') conn.sendmail(sender, receivers, message) print('Success.') conn.close()