Python3 SMTP 'Connection unexpectedly closed' - python-3.x

Could somebody please tell me why I am getting a SMTPServerDisconnected("Connection unexpectedly closed") error from the following code?
import smtplib
from string import Template
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
MY_ADDRESS = '---'
PASSWORD = '---'
def get_contacts(filename):
"""
Return two lists names, emails containing names and email
addresses
read from a file specified by filename.
"""
names = []
emails = []
with open(filename, mode='r', encoding='utf-8') as contacts_file:
for a_contact in contacts_file:
names.append(a_contact.split()[0])
emails.append(a_contact.split()[1])
return names, emails
def read_template(filename):
"""
Returns a Template object comprising the contents of the
file specified by filename.
"""
with open(filename, 'r', encoding='utf-8') as template_file:
template_file_content = template_file.read()
return Template(template_file_content)
def main():
names, emails = get_contacts('contacts.txt') # read contacts
message_template = read_template('message.txt')
# set up the SMTP server
s = smtplib.SMTP('smtp.gmail.com', 465)
s.ehlo()
s.starttls()
s.login(MY_ADDRESS, PASSWORD)
# For each contact, send the email:
for name, email in zip(names, emails):
msg = MIMEMultipart() # create a message
# add in the actual person name to the message template
message =
message_template.substitute(PERSON_NAME=name.title())
# Prints out the message body for our sake
print(message)
# setup the parameters of the message
msg['From']=MY_ADDRESS
msg['To']=email
msg['Subject']="This is TEST"
# add in the message body
msg.attach(MIMEText(message, 'plain'))
# send the message via the server set up earlier.
s.send_message(msg)
del msg
# Terminate the SMTP session and close the connection
s.quit()
if __name__ == '__main__':
main()
Obviously when I run the code my address and password is filled in.
The traceback I get from this when running in terminal is:
Traceback (most recent call last):
File "emailAlert2.py", line 71, in
main()
File "emailAlert2.py", line 40, in main
s = smtplib.SMTP('smtp.gmail.com', 465)
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 251, in init
(code, msg) = self.connect(host, port)
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 338, in connect
(code, msg) = self.getreply()
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 394, in getreply
raise SMTPServerDisconnected("Connection unexpectedly closed")
smtplib.SMTPServerDisconnected: Connection unexpectedly closed
Thanks

The Google Gmail server is hanging up on your (dropping your connection attempt).
Provided that you have enabled third party access (link) to your Gmail account, change your code as follows:
s = smtplib.SMTP('smtp.gmail.com', 465)
s.ehlo()
s.starttls()
s.login(MY_ADDRESS, PASSWORD)
Change to this:
s = smtplib.SMTP_SSL('smtp.gmail.com', 465)
s.ehlo()
s.login(MY_ADDRESS, PASSWORD)
The reason for the hang up is that you are creating a connection using an unencrypted method (smtplib.SMTP()). Google is expecting that you are connecting using SMTPS which requires SSL.

Try port number 587 instead of port 465 in s = smtplib.SMTP('smtp.gmail.com', 465)

Probably you may need to come up with App password instead of your default password - Check this out - https://support.google.com/accounts/answer/185833

Related

How to work around problem with Python smtpd?

I want to make a small SMTP server for testing, using Python, so I was trying the server example code
https://pymotw.com/2/smtpd/
import smtpd
import asyncore
class CustomSMTPServer(smtpd.SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data):
print 'Receiving message from:', peer
print 'Message addressed from:', mailfrom
print 'Message addressed to :', rcpttos
print 'Message length :', len(data)
return
server = CustomSMTPServer(('127.0.0.1', 1025), None)
asyncore.loop()
Together with the example client code on that same page:
import smtplib
import email.utils
from email.mime.text import MIMEText
# Create the message
msg = MIMEText('This is the body of the message.')
msg['To'] = email.utils.formataddr(('Recipient', 'recipient#example.com'))
msg['From'] = email.utils.formataddr(('Author', 'author#example.com'))
msg['Subject'] = 'Simple test message'
server = smtplib.SMTP('127.0.0.1', 1025)
server.set_debuglevel(True) # show communication with the server
try:
server.sendmail('author#example.com', ['recipient#example.com'], msg.as_string())
finally:
server.quit()
However, when I try to run the client, I am getting the following on the server side:
error: uncaptured python exception, closing channel <smtpd.SMTPChannel connected 127.0.0.1:38634 at 0x7fe28a901490> (<class 'TypeError'>:process_message() got an unexpected keyword argument 'mail_options' [/root/Python-3.8.1/Lib/asyncore.py|read|83] [/root/Python-3.8.1/Lib/asyncore.py|handle_read_event|420] [/root/Python-3.8.1/Lib/asynchat.py|handle_read|171] [/root/Python-3.8.1/Lib/smtpd.py|found_terminator|386])
^CTraceback (most recent call last):
File "./mysmtpd.py", line 18, in <module>
asyncore.loop()
File "/root/Python-3.8.1/Lib/asyncore.py", line 203, in loop
poll_fun(timeout, map)
File "/root/Python-3.8.1/Lib/asyncore.py", line 144, in poll
r, w, e = select.select(r, w, e, timeout)
KeyboardInterrupt
Then I found this Issue page:
https://bugs.python.org/issue35837
and I think that that is the problem I've been running into.
That issue hasn't been fixed yet, so I was wondering if, meantime, is there something that I can modify in the example client code that would get around the problem that is described in that issue?
Thanks,
Jim
Add an mail_options=None in your process_message() function.
Just for reference, do the same with the rcpt_options argument.
Ref: https://docs.python.org/3/library/smtpd.html?highlight=process_message#smtpd.SMTPServer.process_message
The error seems to appear
in the line with def process_message(self, peer, mailfrom, rcpttos, data):.
You can replace it with def process_message(self, peer, mailfrom, rcpttos, data,**my_krargs):

NameError with echo client/server test: client unable to send custom message to the server

I'm learning python 3 and is my first language, so sorry if it's a silly question, but I cant't find out why it doesn't work...
I'm testing a simple echo client/server application. According to my book, I first created a file named tincanchat:
import socket
HOST = ''
PORT = 4040
def create_listen_socket(host, port):
""" Setup the sockets our server will receive connection
requests on """
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(100)
return sock
def recv_msg(sock):
""" Wait for data to arrive on the socket, then parse into
messages using b'\0' as message delimiter """
data = bytearray()
msg = ''
# Repeatedly read 4096 bytes off the socket, storing the bytes
# in data until we see a delimiter
while not msg:
recvd = sock.recv(4096)
if not recvd:
# Socket has been closed prematurely
raise ConnectionError()
data = data + recvd
if b'\0' in recvd:
# we know from our protocol rules that we only send
# one message per connection, so b'\0' will always be
# the last character
msg = data.rstrip(b'\0')
msg = msg.decode('utf-8')
return msg
def prep_msg(msg):
""" Prepare a string to be sent as a message """
msg += '\0'
return msg.encode('utf-8')
def send_msg(sock, msg):
""" Send a string over a socket, preparing it first """
data = prep_msg(msg)
sock.sendall(data)
Then, I wrote the server:
import tincanchat
HOST = tincanchat.HOST
PORT = tincanchat.PORT
def handle_client(sock, addr):
""" Receive data from the client via sock and echo it back """
try:
msg = tincanchat.recv_msg(sock) # Blocks until received
# complete message
print('{}: {}'.format(addr, msg))
tincanchat.send_msg(sock, msg) # Blocks until sent
except (ConnectionError, BrokenPipeError):
print('Socket error')
finally:
print('Closed connection to {}'.format(addr))
sock.close()
if __name__ == '__main__':
listen_sock = tincanchat.create_listen_socket(HOST, PORT)
addr = listen_sock.getsockname()
print('Listening on {}'.format(addr))
while True:
client_sock, addr = listen_sock.accept()
print('Connection from {}'.format(addr))
handle_client(client_sock, addr)
And the client:
import sys, socket
import tincanchat
HOST = sys.argv[-1] if len(sys.argv) > 1 else '127.0.0.1'
PORT = tincanchat.PORT
if __name__ == '__main__':
while True:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
print('\nConnected to {}:{}'.format(HOST, PORT))
print("Type message, enter to send, 'q' to quit")
msg = input()
if msg == 'q': break
tincanchat.send_msg(sock, msg) # Blocks until sent
print('Sent message: {}'.format(msg))
msg = tincanchat.recv_msg(sock) # Block until
# received complete
# message
print('Received echo: ' + msg)
except ConnectionError:
print('Socket error')
break
finally:
sock.close()
print('Closed connection to server\n')
I run the server, then the client, which connects with the server and asks for input. At this point, it returns this error:
Connected to 127.0.0.1:4040
Type message, enter to send, 'q' to quit
Hello
Closed connection to server
Traceback (most recent call last):
File "C:\xxxxxxxxx\1.2-echo_client-uni.py", line 22, in <module>
except ConnectionError:
NameError: name 'ConnectionError' is not defined
Where is the problem?
Thanks in advance :)
If u want to catch the specified Errors or Exceptions, U should import them first.
What you could do for for example is:
from requests.exceptions import ConnectionError
try:
r = requests.get("http://example.com", timeout=0.001)
except ConnectionError as e: # This is the correct syntax
print e
r = "No response"
In this case your program will not return 'NameError'

Python - Cannot Send Email

I am running Python 3.4.2, on Windows 7 Enterprise, 64 bit.
I have the below script (write_email.py) that receives an error when run:
# smtplib module send mail
import smtplib
TO = 'address#somedomain.com'
SUBJECT = 'TEST MAIL'
TEXT = 'Here is a message from python.'
# Gmail Sign In
gmail_sender = 'address#gmail.com'
gmail_passwd = '' #this is left blank on purpose
server = smtplib.SMTP('smtp-relay.gmail.com', 25)
server.ehlo()
server.starttls()
server.login(gmail_sender, gmail_passwd)
BODY = '\r\n'.join(['To: %s' % TO,
'From: %s' % gmail_sender,
'Subject: %s' % SUBJECT,
'', TEXT])
try:
server.sendmail(gmail_sender, [TO], BODY)
print ('email sent')
except:
print ('error sending mail')
server.quit()
The error is:
Traceback (most recent call last):
File "email_test.py", line 17, in <module>
server.login(gmail_sender, gmail_passwd)
File "C:\Python34\lib\smtplib.py", line 652, in login
raise SMTPAuthenticationError(code, resp)
smtplib.SMTPAuthenticationError: (501, b'5.5.2 Cannot Decode response 13sm147030
88ith.4 - gsmtp')
I've done a lot of searching to resolve this, but so far no luck.

Can Someone Please Tell Me What This Code Does

import imaplib,time
class Mail():
def __init__(self):
self.user= 'USERNAME'
self.password= 'PASSWORD'
self.M = imaplib.IMAP4_SSL('imap.gmail.com', '993')
self.M.login(self.user, self.password)
def checkMail(self):
self.M.select()
self.unRead = self.M.search(None, 'UnSeen')
return len(self.unRead[1][0].split())
email = Mail()
while 1:
print ('Sending')
time.sleep(2)
You initialize a class called Mail that supposedly uses the imaplib library to check the unread messages of a gmail account. However, after you assign email to an instance of Mail, your while loop, which is responsible for the action in your code, is comprised of two events; a print and a time.sleep().
So your code essentially is a long way of printing 'Sending' every 2 seconds.
Running after commenting out the line email = Mail() due to invalid credentials
bash-3.2$ python foo.py
Sending
Sending
^CTraceback (most recent call last):
File "foo.py", line 21, in <module>
time.sleep(2)
KeyboardInterrupt
bash-3.2$

Telnet.read.until function doesn't work

Trying to telnet to a Brocade router and the python script is sending out error.... Not sure what is wrong here. Have tried a debug but cant make it working. I believe it's prompt issue. I appreciate if anyone has suggestion how to get it work.
Note: This is Python 3.0
import getpass
import sys
import telnetlib
HOST = "1.1.1.1"
user = "admin"
password = "password"
port = "23"
telnet = telnetlib.Telnet(HOST)
telnet.read_until("sw0 login:,3")
telnet.write(admin + "\r")
if password:
telnet.read_until("Password: ")
telnet.write(password + "\n")
tn.write("term len 0" + "\n")
telnet.write("sh ver br\n")
telnet.write("exit\n")
ERROR:
Traceback (most recent call last):
File "C:\Users\milan\Desktop\telnetNew.py", line 13, in <module>
telnet.read_until("Username :,3")
File "C:\Python33\lib\telnetlib.py", line 299, in read_until
return self._read_until_with_select(match, timeout)
File "C:\Python33\lib\telnetlib.py", line 352, in _read_until_with_select
i = self.cookedq.find(match)
TypeError: Type str doesn't support the buffer API
This is my prompt after logging manually using telnet port 23 and this is what i expected command to work.
_________________________________________________________________________________
Network OS (sw0)
xxxxxxxxxx
sw0 login: xxxxx
Password: xxxxx
WARNING: The default password of 'admin' and 'user' accounts have not been changed.
Welcome to the Brocade Network Operating System Software
admin connected from 10.100.131.18 using console on sw0
sw0# sh ver
sw0#
In looking at the docs, it appears that telnetlib want a bytestr, not a Str. so try this., which should convert everything to bytes as opposed to Str
import sys
import telnetlib
HOST = "1.1.1.1"
user = "admin"
password = "password"
port = "23"
telnet = telnetlib.Telnet(HOST,port)
telnet.read_until(b"login: ")
telnet.write(admin.encode('ascii') + b"\n")
telnet.read_until(b"Password: ")
telnet.write(password.encode('ascii') + b"\n")
tn.write(b"term len 0\n")
telnet.write(b"sh ver br\n")
telnet.write(b"exit\n")
--edit-- I installed python and tried this against one of my routers. Changing the username/password to my credentials I was able to login fine. ( I removed the password check and the getpass as they where not being used, being that your code has them hardcoded). It looks like you copied the 2.x example, but the 3.x requires the buffer compatible ones without the b" i Get this
Traceback (most recent call last):
File "foo.py", line 5, in <module>
telnet.read_until("login: ")
File "/usr/local/Cellar/python32/3.2.5/Frameworks/Python.framework/Versions/3.2/lib/python3.2/telnetlib.py", line 293, in read_until
return self._read_until_with_poll(match, timeout)
File "/usr/local/Cellar/python32/3.2.5/Frameworks/Python.framework/Versions/3.2/lib/python3.2/telnetlib.py", line 308, in _read_until_with_poll
i = self.cookedq.find(match)
TypeError: expected an object with the buffer interface
with the b" I get
[~] /usr/local/bin/python3.2 foo.py
b'\r\n\r\nThis computer system including all related equipment, network devices\r\n(specifically including Internet access), are provided only for\r\nauthorized use. All computer
which shows it is working.. what errors are you getting now
import telnetlib , socket
class TELNET(object):
def __init__(self):
self.tn = None
self.username = "root"
self.password = "12345678"
self.host = "10.1.1.1"
self.port = 23
self.timeout = 5
self.login_prompt = b"login: "
self.password_prompt = b"Password: "
def connect(self):
try :
self.tn = telnetlib.Telnet(self.host,self.port,self.timeout)
except socket.timeout :
print("TELNET.connect() socket.timeout")
self.tn.read_until(self.login_prompt, self.timeout)
self.tn.write(self.username.encode('ascii') + b"\n")
if self.password :
self.tn.read_until(self.password_prompt,self.timeout)
self.tn.write(self.password.encode('ascii') + b"\n")
def write(self,msg):
self.tn.write(msg.encode('ascii') + b"\n")
return True
def read_until(self,value):
return self.tn.read_until(value)
def read_all(self):
try :
return self.tn.read_all().decode('ascii')
except socket.timeout :
print("read_all socket.timeout")
return False
def close(self):
self.tn.close()
return True
def request(self,msg):
self.__init__()
self.connect()
if self.write(msg) == True :
self.close()
resp = self.read_all()
return resp
else :
return False
telnet = TELNET()
#call request function
resp = telnet.request('ps www') # it will be return ps output
print(resp)
That code works on python3
Most of these answers are great in-depth explanations and I found them a little hard to follow. The short answer is that the Sample code is wrong on the Python 3x site.
to fix this, instead of
' telnet.read_until("Username :,3")'
use
' telnet.read_until(b"Username :,3")'
Like the other answers say, the problem is that Telnetlib expects byte strings. In Python 2 the str type is a byte string (a string of binary data) whereas it's a unicode string in Python 3 and a new bytes type that represents binary data in the same was as str did in Python 2.
The upshot of this is that you need to convert your str data into bytes data when using Telnetlib in Python 3. I have some code that works in both Python2 and Python3 that I thought worth sharing.
class Telnet(telnetlib.Telnet,object):
if sys.version > '3':
def read_until(self,expected,timeout=None):
expected = bytes(expected, encoding='utf-8')
received = super(Telnet,self).read_until(expected,timeout)
return str(received, encoding='utf-8')
def write(self,buffer):
buffer = bytes(buffer, encoding='utf-8')
super(Telnet,self).write(buffer)
def expect(self,list,timeout=None):
for index,item in enumerate(list):
list[index] = bytes(item, encoding='utf-8')
match_index, match_object, match_text = super(Telnet,self).expect(list,timeout)
return match_index, match_object, str(match_text, encoding='utf-8')
You then instantiate the new Telnet class instead of telnetlib.Telnet. The new class overrides methods in Telnetlib to perform conversion from str to bytes and bytes to str so that the problem just goes away.
Of course, I've only overriden the methods that I was using, but it should be clear from the example how to extend the idea to other methods. Basically, you need to use
bytes(str_string, encoding='utf-8')
and
str(bytes_string, encoding='utf-8')
My code is valid Python 2 and 3 so will work unmodified with either interpreter. When in Python2 the code that overrides the methods is skipped over, effectively ignored. If you don't care for backwards compatibility you can remove the condition that checks for the Python version.

Resources