El módulo smtplib
no incluye la funcionalidad para conectarse a un servidor SMTP a través de un proxy HTTP. El custom class posted by 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 [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
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 conectar con el servidor SMTP, sólo tiene que utilizar la clase ProxySMTP
en 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 = '[email protected]'
receivers = ['[email protected]']
message = """From: From Person <[email protected]>
To: To Person <[email protected]>
Subject: SMTP e-mail test
This is a test e-mail message.
"""
print('Send email.')
conn.sendmail(sender, receivers, message)
print('Success.')
conn.close()
Parece que no está enviando el correo electrónico, simplemente se queda allí y cuelga. Intenté con un par de proxies diferentes también. – Sinista
Como dice @Sinista, su código no funciona, en su lugar, simplemente se queda allí y se cuelga. Me tomé la libertad de arreglarlo, así que ahora está funcionando bien para mí. [Ver mi respuesta] (http://stackoverflow.com/a/31348278/3718878). – Zenadix