From 0c4273c552e23b6aa635d155b35caa45dc6f937e Mon Sep 17 00:00:00 2001 From: wangande Date: Tue, 14 Jun 2016 13:37:13 +0800 Subject: [PATCH] add http proxy set --- testproject.py | 5 +++- tornadomail/backends/smtp.py | 12 +++++----- tornadomail/smtplib.py | 44 ++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/testproject.py b/testproject.py index 33fa06d..3d617f3 100755 --- a/testproject.py +++ b/testproject.py @@ -22,7 +22,10 @@ class Application(tornado.web.Application): def mail_connection(self): return EmailBackend( 'smtp.gmail.com', 587, '', '', - True + True, + #proxy_host="proxy_host", + #proxy_port=proxy_port, + ) class MainHandler(tornado.web.RequestHandler): diff --git a/tornadomail/backends/smtp.py b/tornadomail/backends/smtp.py index cdc9770..0cc771a 100644 --- a/tornadomail/backends/smtp.py +++ b/tornadomail/backends/smtp.py @@ -26,6 +26,8 @@ def __init__(self, host=None, port=None, username=None, password=None, self.use_tls = use_tls self.connection = None self.template_loader = kwargs.get('template_loader', None) + self.proxy_host = kwargs.get('proxy_host', None) + self.proxy_port = kwargs.get('proxy_port', None) @gen.engine def open(self, callback): @@ -40,7 +42,7 @@ def open(self, callback): # If local_hostname is not specified, socket.getfqdn() gets used. # For performance, we use the cached FQDN for local_hostname. self.connection = smtplib.SMTP(self.host, self.port, - local_hostname=DNS_NAME.get_fqdn()) + local_hostname=DNS_NAME.get_fqdn(), proxy_host=self.proxy_host, proxy_port=self.proxy_port) yield gen.Task(self.connection.connect, self.host, self.port) if self.use_tls: yield gen.Task(self.connection.ehlo) @@ -53,12 +55,11 @@ def open(self, callback): if not self.fail_silently: raise - @gen.engine - def close(self,callback): + def close(self): """Closes the connection to the email server.""" try: try: - yield gen.Task(self.connection.quit) + self.connection.quit() except socket.sslerror: # This happens when calling quit() on a TLS connection # sometimes. @@ -69,7 +70,6 @@ def close(self,callback): raise finally: self.connection = None - callback(None) @gen.engine def send_messages(self, email_messages, callback=None): @@ -91,7 +91,7 @@ def send_messages(self, email_messages, callback=None): if sent: num_sent += 1 if new_conn_created: - yield gen.Task(self.close) + self.close() if callback: callback(num_sent) diff --git a/tornadomail/smtplib.py b/tornadomail/smtplib.py index 40ae28c..9019999 100644 --- a/tornadomail/smtplib.py +++ b/tornadomail/smtplib.py @@ -228,7 +228,7 @@ class SMTP: does_esmtp = 0 def __init__(self, host, port=0, local_hostname=None, - timeout=socket._GLOBAL_DEFAULT_TIMEOUT): + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, proxy_host=None, proxy_port=None): """Initialize a new instance. If specified, `host' is the name of the remote host to which to @@ -243,6 +243,8 @@ def __init__(self, host, port=0, local_hostname=None, self.esmtp_features = {} self.default_port = SMTP_PORT self.local_hostname = local_hostname or 'localhost' + self.proxy_host = proxy_host + self.proxy_port = proxy_port #if host: # (code, msg) = self.connect(host, port) # if code != 220: @@ -256,6 +258,35 @@ def set_debuglevel(self, debuglevel): """ self.debuglevel = debuglevel + + def _get_socket2(self, port, host, timeout): + # sync get proxy connect + if hasattr(self, '__get_socket'): + return self.__get_socket + if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + #s = socket.create_connection(("10.0.1.62", 3128), timeout) + s.connect((self.proxy_host, self.proxy_port)) + + fp = s.makefile("r+") + # # _send_str = "CONNECT %s:%s HTTP/1.1\r\n\r\nhost: %s\r\n\r\n" % (host, port, host) + # _send_str = "CONNECT %s:%s HTTP/1.1\r\n\r\nhost: %s\r\n\r\nProxy-Authorization: guest idealsee2016\r\n\r\n" % (self.proxy_host, self.proxy_port, self.proxy_host) + # _send_str = _send_str.encode("UTF-8") + # fp.write(_send_str) + # fp.flush() + + # fp = s.makefile("r+") + _send_str = "CONNECT %s:%s HTTP/1.1\r\n\r\nhost: %s\r\n\r\n" % (host, port, host) + _send_str = _send_str.encode("UTF-8") + fp.write(_send_str) + fp.flush() + + status_line = fp.readline().rstrip("\r\n") + if 'HTTP' in status_line and ('200' not in status_line): + raise SMTPConnectError(200,'proxy(%s, %s) connect to (%s, %s) failed, status_line is : %s'%(self.proxy_host, self.proxy_port, host, port, status_line)) + stream = iostream.IOStream(s) + self.__get_socket = stream + return stream def _get_socket(self, port, host, timeout, callback): # This makes it simpler for SMTP_SSL to use the SMTP connect code @@ -305,10 +336,13 @@ def connect(self, host='localhost', port = 0, callback=None): except ValueError: raise socket.error, "nonnumeric port" if not port: port = self.default_port - result = yield gen.Task( - self._get_socket, port, host, self.timeout - ) - self.sock = result.kwargs['socket'] + if self.proxy_host and self.proxy_port: + self.sock = self._get_socket2(port, host, self.timeout) + else: + result = yield gen.Task( + self._get_socket, port, host, self.timeout + ) + self.sock = result.kwargs['socket'] if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) result = yield gen.Task(self.getreply) (code, msg) = result.args