我想通过代理发送电子邮件。Python smtplib代理支持
我目前的实施情况如下。
我通过身份验证连接到smtp服务器。成功登录后,我发送一封电子邮件。它工作正常,但是当我看到电子邮件标题时,我可以看到我的主机名。我想通过代理来代替它。
任何帮助将不胜感激。
我想通过代理发送电子邮件。Python smtplib代理支持
我目前的实施情况如下。
我通过身份验证连接到smtp服务器。成功登录后,我发送一封电子邮件。它工作正常,但是当我看到电子邮件标题时,我可以看到我的主机名。我想通过代理来代替它。
任何帮助将不胜感激。
我昨天有类似的问题,这是我写的代码来解决问题。它无形中允许你通过代理使用所有的smtp方法。
#!/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 [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_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
的smtplib
模块不包括的功能通过HTTP代理服务器连接到SMTP服务器。 custom class posted by ryoh没有为我工作,显然是因为我的HTTP代理只接收编码消息。我编写了基于ryos代码的以下自定义类,并且它工作正常。
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
要连接到SMTP服务器,只需使用类ProxySMTP
,而不是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()
什么是错误220? 该代码引发了IOError,Received行:HTTP/1.1 412先决条件失败,已接收的行:Cache-Control:no-cache,IOError:[Errno -1] ma:no-cache – 2015-09-11 15:28:07
您的代码无法运行。导致错误 - AttributeError:ProxySMTP实例没有属性'local_hostname' – 2016-04-08 09:10:55
此代码已从我赚取。 1.文件名不能是email.py重命名文件名,例如emailSend.py 2.有必要允许Google发送来自不可靠来源的消息。
似乎没有发送电子邮件,它只是坐在那里,挂起。也尝试过一些不同的代理。 – Sinista 2012-01-11 16:39:53
正如@Sinista所说,你的代码不起作用,它只是坐在那里并挂起。我已经自由修复它,现在它对我来说工作得很好。 [看我的回答](http://stackoverflow.com/a/31348278/3718878)。 – Zenadix 2015-07-10 19:05:08