Python SMTPD library override version - python

I'd like to emit my own message when someone connects to this smtp server.
import smtpd
import asyncore
class FakeSMTPServer(smtpd.SMTPServer):
__version__ = 'TEST EMAIL SERVER'
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
if __name__ == "__main__":
smtp_server = FakeSMTPServer(('localhost', 25), None)
try:
asyncore.loop()
except KeyboardInterrupt:
smtp_server.close()
However, I am still getting the response:
220 Win7-PC Python SMTP proxy version 0.2
How do I override the welcome message in python to see "TEST EMAIL SERVER"?

Just do
smtpd.__version__ = "TEST EMAIL SERVER"
somewhere (may be after import statements).

Related

Using smtplib to send an email to mailtrap only works when code is not within function or class

this question is somehow similar to python: sending a mail, fails when inside a "with" block .
I'm using Python (3.6) to send emails to mailtrap smtp. Mailtrap actually provides you with the integration code for smtplib which is the one below:
import smtplib
sender = "Private Person <from#smtp.mailtrap.io>"
receiver = "A Test User <to#smtp.mailtrap.io>"
message = f"""\
Subject: Hi Mailtrap
To: {receiver}
From: {sender}
This is a test e-mail message."""
with smtplib.SMTP("smtp.mailtrap.io", 2525) as server:
server.login("<MYUSER>", "<MYPASSWORD>")
server.sendmail(sender, receiver, message)
The code above works just fine if I place it in a module and run it.I go to mailtrap inbox and verify that the email is there. However I want to encapsulate this in a function like this:
import smtplib
from socket import gaierror
def test():
sender = "Test Dev <from#smtp.mailtrap.io>"
receiver = "Test User <to#smtp.mailtrap.io>"
message = f"""\
Subject: Hi there
To: {receiver}
From: {sender}
TESTING"""
try:
with smtplib.SMTP("smtp.mailtrap.io", 2525) as server:
server.login("<MYUSER>", "<MYPASSWORD")
print("Sending email")
server.sendmail(sender, receiver, message)
print('Sent')
except (gaierror, ConnectionRefusedError):
print('Failed to connect to the server. Bad connection settings?')
except smtplib.SMTPServerDisconnected:
print('Failed to connect to the server. Wrong user/password?')
except smtplib.SMTPException as e:
print('SMTP error occurred: ' + str(e))
if __name__ == "__main__":
test()
This doesn't work. WHY? Here is the output:
output image
There's no connection error or any other exception. However I go to mailtrap and don't find the email there.
Is this a mailtrap issue or is it related to smtplib ? I'm cracking my head around this one
I was having this same issue and couldn't wrap my head around it. I did notice that when I made my message an empty string, it worked.
After an embarrassingly long time of searching; I found this post which pointed me to the solution.
You must set the MIME type of the email message. So rather than just passing a string you pass a message object:
message = MIMEText("TEST!")
message["Subject"] = "Alert!"
message["From"] = sender
message["To"] = receiver
... then eventually
server.sendmail(sender, receiver, message.as_string())
my full send email function looks like this:
def send_mail(self):
message = MIMEText("TEST!")
message["Subject"] = "Alert!"
message["From"] = sender
message["To"] = receiver
try:
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
server.set_debuglevel(1)
server.ehlo() # Can be omitted
server.starttls(context=context)
server.ehlo() # Can be omitted
server.login(login, password)
server.sendmail(sender, receiver, message.as_string())
print('Sent')
except (gaierror, ConnectionRefusedError):
print('Failed to connect to the server. Bad connection settings?')
except smtplib.SMTPServerDisconnected:
print('Failed to connect to the server. Wrong user/password?')
except smtplib.SMTPException as e:
print('SMTP error occurred: ' + str(e))
except Exception as e:
print('everything else')
It's unfortunate that you must specify the sender and receiver in both the message object and sendemail fuction.

How do I send an email to my python server?

I've written a small smtp server in python (taken from the smtpd docs):
import smtpd
import asyncore
class MySMTPServer(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 = MySMTPServer(('127.0.0.1', 587), None)
asyncore.loop()
I want to be able to send an email from my gmail account (or whatever email provider) to this server. Here's what I've done so far:
Write an MX record on an A-Level domain
Throw the server up on a box that has port 587 opened
Send an email from gmail to someone#myaleveldomain.com
Profit?
Step 4 hasn't really come through. I can't find any logs that offer any info into what happened, according to my server logs the message from gmail never arrived.
Am I doing something wrong? Please help!

Sending mail through Python SMTP Server

I am trying to build a small SMTP Server through which I can be able to send some messages. Looking at the smtpd library found that there was something. But I only was able to create a server that reads the email received, but never sent it to the address requested.
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()
client:
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', ['myadress#gmail.com'], msg.as_string())
finally:
server.quit()
If you really want to do this
then check out the Twisted examples:
http://twistedmatrix.com/documents/current/mail/examples/index.html#auto0
I really don't recommend you write your own MTA (Mail Transfer Agent) as this is
a complex task with many edge cases and standards to have to worry about.
Use an existing MTA such as Postfix, Exim, or Sendmail.

Why Do I Keep getting SSL Error on Simple Mail Client Program? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implementing Transport Layer Security in Python - Simple Mail Client
I keep getting this error...
ssl.SSLError: [Errno 185090050] _ssl.c:340: error:0B084002:x509 certificate routines:X509_load_cert_crl_file:system lib
...in a simple mail client assignment which is to open a connection with a google smtp server. The problem almost certainly seems to be in the way I am forming the ssl.wrap_socket() method here....
clientSocket = socket(AF_INET, SOCK_STREAM)
ssl_clientSocket = ssl.wrap_socket(clientSocket,
ca_certs = '/etc/ssl/certs/ca.pm',
cert_reqs = ssl.CERT_REQUIRED)
ssl_clientSocket.connect((mailserver, port))
.. but I can't really figure out exactly what the problem is, and I'm really not sure which .pm file to use in /etc/ssl/certs. I'm using ca.pm because I've seen it done that way in a few tutorials. Here is the remainder of the code for good measure....
from socket import *
import certifi
import ssl
msg = "\r\n I love computer networks!"
endmsg = "\r\n.\r\n"
# Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = "smtp.gmail.com"
port = 587
# Create socket called clientSocket and establish a TCP connection with mailserver
clientSocket = socket(AF_INET, SOCK_STREAM)
ssl_clientSocket = ssl.wrap_socket(clientSocket,
ca_certs = '/etc/ssl/certs/ca.pm',
cert_reqs = ssl.CERT_REQUIRED)
ssl_clientSocket.connect((mailserver, port))
###################################################################
print "got to here 1"
###############################################################
recv = ssl_clientSocket.recv(1024)
print
print recv
# If the first three numbers of what we receive from the SMTP server are not
# '220', we have a problem
if recv[:3] != '220':
print '220 reply not received from server.'
# Send HELO command and print server response.
heloCommand = 'HELO Alice\r\n'
ssl_clientSocket.send(heloCommand)
recv1 = ssl_clientSocket.recv(1024)
print recv1
######################################################################
print "Got to here 2"
#####################################################################
# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv1[:3] != '250':
print '250 reply not received from server.'
# Send MAIL FROM command and print server response.
mailFromCommand = 'MAIL From: wgimson#gmail.com\r\n'
ssl_clientSocket.send(mailFromCommand)
recv2 = ssl_clientSocket.recv(1024)
print recv2
# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv2[:3] != '250':
print '250 reply not received from server.'
# Send RCPT TO command and print server response.
rcptToCommand = 'RCPT To: macyali#gmail.com\r\n'
ssl_clientSocket.send(rcptToCommand)
recv3 = ssl_clientSocket.recv(1024)
print recv3
# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv3[:3] != '250':
print '250 reply not received from server.'
# Send DATA command and print server response.
dataCommand = 'DATA\r\n'
ssl_clientSocket.send(dataCommand)
recv4 = ssl_clientSocket.recv(1024)
print recv4
# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv4[:3] != '250':
print '250 reply not received from server.'
# Send message data.
ssl_clientSocket.send(msg)
# Message ends with a single period.
ssl_clientSocket.send(endmsg)
# Send QUIT command and get server response.
quitCommand = 'QUIT\r\n'
ssl_clientSocket.send(quitCommand)
recv5 = ssl_clientSocket.recv(I1024)
print recv5
# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv5[:3] != '221':
print '221 reply not received from server.'
the error might be caused by a typo: '/etc/ssl/certs/ca.pm' -> '/etc/ssl/certs/ca.pem'
i.e., the system can't find ca.pm file
'/etc/ssl/certs/ca.pem' doesn't contain necessary CA certs.
You could download cacert.pem from http://curl.haxx.se/ca/cacert.pem (it is more current) or use ca_certs = certifi.where() (I see import certifi in your code), example:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import smtplib
import socket
import ssl
import sys
from email.header import Header
from email.mime.text import MIMEText
from getpass import getpass
import certifi # $ pip install certifi
login, password = 'user#gmail.com', getpass('Gmail password:')
ca_certs = certifi.where()
##ca_certs = 'cacert.pem' # $ wget http://curl.haxx.se/ca/cacert.pem
class SMTP_SSL(smtplib.SMTP_SSL):
"""Add support for additional ssl options."""
def __init__(self, host, port=0, **kwargs):
self.ssl_kwargs = kwargs.pop('ssl_kwargs', {})
self.ssl_kwargs['keyfile'] = kwargs.pop('keyfile', None)
self.ssl_kwargs['certfile'] = kwargs.pop('certfile', None)
smtplib.SMTP_SSL.__init__(self, host, port, **kwargs)
def _get_socket(self, host, port, timeout):
if self.debuglevel > 0:
print>>sys.stderr, 'connect:', (host, port)
new_socket = socket.create_connection((host, port), timeout)
new_socket = ssl.wrap_socket(new_socket, **self.ssl_kwargs)
self.file = smtplib.SSLFakeFile(new_socket)
return new_socket
# create message
msg = MIMEText('message body…', _charset='utf-8')
msg['Subject'] = Header('subject…', 'utf-8')
msg['From'] = login
msg['To'] = login
# send it via gmail
s = SMTP_SSL('smtp.gmail.com', timeout=10,
ssl_kwargs=dict(cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_SSLv3,
ca_certs=ca_certs))
s.set_debuglevel(1) # enable debug output
try:
s.login(login, password)
s.sendmail(msg['From'], msg['To'], msg.as_string())
finally:
s.quit()

Detecting socket close with Python's asyncore and smtpd

Python newbie here. I'm using asyncore and smtpd to write an email server. Everything seems to work except that I can't figure out how to detect when/if the connecting client closes the socket. Also, I can't seem to set a timeout to automatically close connections after inactivity. Here's some example code. CustomSTMPServer.handle_close is never called. And I don't know how to set a timeout that works. Any help would be greatly appreciated.
import smtpd
import asyncore
class CustomSMTPServer(smtpd.SMTPServer):
def handle_accept(self):
pair = self.accept()
if pair is None:
pass
conn, addr = pair
print 'Incoming connection from %s' % addr[0]
channel = smtpd.SMTPChannel(self, conn, addr)
def handle_close(self):
print 'Received close'
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()

Categories

Resources