프록시를 통해 전자 메일을 보내고 싶습니다.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
은
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()
무엇이 오류 220입니까? HTTP/1.1 412 전제 조건 실패, 수신 회선 : 캐시 제어 : no-cache, IOError : [Errno -1] ma : no-cache –
코드가 작동하지 않습니다. 문제가 발생했습니다 - AttributeError : ProxySMTP 인스턴스에 'local_hostname'속성이 없습니다. –
이 코드는 나에게서 받았다. 1. 파일 이름은 email.py가 아니어야합니다. 파일 이름의 이름 바꾸기 (예 : emailSend.py ) 2. Google에서 신뢰할 수없는 출처의 메시지를 보낼 수 있도록해야합니다.
이메일을 보내는 것처럼 보이지 않습니다. 그냥 앉아서 멈춰 있습니다. 몇 가지 다른 프록시를 사용해 보았습니다. – Sinista
@Sinista는 코드가 작동하지 않는다고 말하면서 그냥 앉아서 멈 춥니 다. 나는 그것을 고칠 자유를 취 했으므로 이제는 나를 위해 잘 작동한다. [내 대답보기] (http://stackoverflow.com/a/31348278/3718878). – Zenadix