Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion testproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ class Application(tornado.web.Application):
def mail_connection(self):
return EmailBackend(
'smtp.gmail.com', 587, '<your google email>', '<your google password>',
True
True,
#proxy_host="proxy_host",
#proxy_port=proxy_port,

)

class MainHandler(tornado.web.RequestHandler):
Expand Down
12 changes: 6 additions & 6 deletions tornadomail/backends/smtp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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)
Expand All @@ -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.
Expand All @@ -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):
Expand All @@ -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)

Expand Down
44 changes: 39 additions & 5 deletions tornadomail/smtplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down