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
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.
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!
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.
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()
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()