2011-03-08 70 views
5

我想通过代理发送电子邮件。Python smtplib代理支持

我目前的实施情况如下。

我通过身份验证连接到smtp服务器。成功登录后,我发送一封电子邮件。它工作正常,但是当我看到电子邮件标题时,我可以看到我的主机名。我想通过代理来代替它。

任何帮助将不胜感激。

回答

4

我昨天有类似的问题,这是我写的代码来解决问题。它无形中允许你通过代理使用所有的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 
+1

似乎没有发送电子邮件,它只是坐在那里,挂起。也尝试过一些不同的代理。 – Sinista 2012-01-11 16:39:53

+1

正如@Sinista所说,你的代码不起作用,它只是坐在那里并挂起。我已经自由修复它,现在它对我来说工作得很好。 [看我的回答](http://stackoverflow.com/a/31348278/3718878)。 – Zenadix 2015-07-10 19:05:08

-1

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() 
+0

什么是错误220? 该代码引发了IOError,Received行:HTTP/1.1 412先决条件失败,已接收的行:Cache-Control:no-cache,IOError:[Errno -1] ma:no-cache – 2015-09-11 15:28:07

+0

您的代码无法运行。导致错误 - AttributeError:ProxySMTP实例没有属性'local_hostname' – 2016-04-08 09:10:55

0

此代码已从我赚取。 1.文件名不能是email.py重命名文件名,例如emailSend.py 2.有必要允许Google发送来自不可靠来源的消息。