2011-03-08 8 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

+1

@Sinista는 코드가 작동하지 않는다고 말하면서 그냥 앉아서 멈 춥니 다. 나는 그것을 고칠 자유를 취 했으므로 이제는 나를 위해 잘 작동한다. [내 대답보기] (http://stackoverflow.com/a/31348278/3718878). – Zenadix

-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 

smtplib.SMTP 대신 클래스 ProxySMTP를 사용하여 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입니까? HTTP/1.1 412 전제 조건 실패, 수신 회선 : 캐시 제어 : no-cache, IOError : [Errno -1] ma : no-cache –

+0

코드가 작동하지 않습니다. 문제가 발생했습니다 - AttributeError : ProxySMTP 인스턴스에 'local_hostname'속성이 없습니다. –

0

이 코드는 나에게서 받았다. 1. 파일 이름은 email.py가 아니어야합니다. 파일 이름의 이름 바꾸기 (예 : emailSend.py ) 2. Google에서 신뢰할 수없는 출처의 메시지를 보낼 수 있도록해야합니다.

관련 문제