J'ai eu le temps d'améliorer un peu le prototype, en utilisant le package email notamment pour convertir les données brutes du mail en objet facilement manipulable.
Concernant la classe de base, j'ai rajouté le comportement correct pour la commande smtp "EHLO" : on renvoie la réponse 502, ce qui indique à Thunderbird que mon serveur est un serveur smtp et non esmtp (Google a été mon ami sur ce coup là, mais j'ai oublié de noter l'url)
L'extrait de code, à rajouter après la section traitant la commande "HELO" :
elif cmd == "EHLO":
return("502 Command not implemented", keep)
Et voici le code de mon serveur. Celui-ci gère maintenant les destinataire (to, cc, bcc), par contre, pour les mails en multiple partie (pièces jointes, texte html etc) je ne fais que concaténer les partie dont le type de contenu contient "text/". Quoiqu'il en soit, c'est maintenant utilisable pour le besoin de base, l'envoi d'un message ou d'une réponse à plusieurs.
# (c)2009 David SPORN
#
# A brain-dead Python SMTP to MAPI relay server based on the smtps, smtplib and mapi
# packages.
#
# DISCLAIMER
# You are free to use this code in any way you like, subject to the
# Python disclaimers & copyrights. I make no representations about the
# suitability of this software for any purpose. It is provided "AS-IS"
# without warranty of any kind, either express or implied. So there.
#
# Sources
# http://code.activestate.com/recipes/149461/
# smtps.py
"""
smtp2mapi.py -- A very simple & dumb Python SMTP to MAPI relay server. It uses
smtps for the server side and MAPI for the client side. This is
intended for use as a proxy to an Exchange server that is restricted to MAPI
(e.g. for 'security purpose').
This blocks, waiting for RFC821 messages from clients on the given
port. When a complete SMTP message is received, it connect to the
Exchange server using the Outlook OLE component, convert the
message and send it. Obviously, Outlook must be present.
All processing is single threaded. It generally handles errors
badly. It fails especially badly if DNS or the resolved mail host
hangs. DNS or mailhost failures are not propagated back to the client,
which is bad news.
The mail address 'shutdown@shutdown.now' is interpreted
specially. This gets around a Python 1.5/Windows/WINSOCK bug that
prevents this script from being interrupted.
"""
import sys
import smtps
import string
import smtplib
import email
import StringIO
import win32com.client.dynamic
import re
from email.feedparser import FeedParser
#Default Mapi profile
DEFAULT_MAPI_PROFILE = "Outlook"
#
#
# This extends the smtps.SMTPServerInterface and specializes it to
# proxy requests onwards. It uses DNS to resolve each RCPT TO:
# address, then uses smtplib to forward the client mail on the
# resolved mailhost.
#
class SMTPService(smtps.SMTPServerInterface):
def initMapi(self):
self.outlook = win32com.client.dynamic.Dispatch("Outlook.Application")
self.mapi = self.outlook.GetNamespace("MAPI")
self.mapi.Logon(DEFAULT_MAPI_PROFILE)
def quitMapi(self):
self.mapi.Logoff()
self.mapi = None
def __init__(self):
self.savedTo = []
self.savedMailFrom = ''
self.shutdown = 0
self.initMapi()
def mailFrom(self, args):
# Stash who its from for later
self.savedMailFrom = smtps.stripAddress(args)
def rcptTo(self, args):
# Stashes multiple RCPT TO: addresses
self.savedTo.append(args)
def data(self, args):
data = args
#check for shutdown command
for addressee in self.savedTo:
toHost, toFull = smtps.splitTo(addressee)
# Treat this TO address speciallt. All because of a
# WINSOCK bug!
if toFull == 'shutdown@shutdown.now':
self.shutdown = 1
return
#sys.stdout.write('Adding recipient ' + toFull + '...\n\r')
#recipients.Add(toFull)
#
#
message = self.outlook.CreateItem(0)
#
#data parsing...
e_mail = self.getEmailMessage(data)
header = self.getMessageRawHeader(args)
subject=e_mail['Subject']
dest_to = e_mail['To']
dest_cc = e_mail['Cc']
dest_bcc = e_mail['Bcc']
#
#recipientprocessing
recipients = message.Recipients
if (None != dest_to):
#print "To :\n\r"+dest_to
self.appendRecipient(recipients, dest_to, 1)
if (None != dest_cc):
#print "CC :\n\r"+dest_cc
self.appendRecipient(recipients, dest_cc, 2)
if (None != dest_bcc):
#print "BCC :\n\r"+dest_bcc
self.appendRecipient(recipients, dest_bcc, 3)
#
#subject processing
if (None != subject):
message.Subject = subject
else:
message.Subject = ""
#
#message processing
if (e_mail.is_multipart()):
#attachements = message.Attachements
#attache each textual parts to the messsage
the_body = ""
for part in e_mail.walk():
if (-1 != string.find(part.get_content_type(), 'text/')):
the_body = the_body + part.get_payload()
message.Body = the_body
else:
message.Body = e_mail.get_payload()
sys.stdout.write('Sending message...\n\r')
message.Send()
self.savedTo = []
def quit(self, args):
if self.shutdown:
print 'Shutdown at user request\n\r'
sys.exit(0)
def frobData(self, data):
hend = string.find(data, '\n\r')
if hend != -1:
rv = data[:hend]
else:
rv = data[:]
rv = rv + 'X-Sporniket: Python SMTP to MAPI Relay'
rv = rv + data[hend:]
return rv
def getSubject(self, data):
hstart = string.find(data, 'Subject: ')
if hstart != -1:
rv = data[hstart+9:]
else:
return ''
hend = string.find(rv, '\n')
if hend != -1:
rv = rv[:hend]
else:
rv = rv[:]
return rv
def getMessageRawHeader(self, data):
hend = string.find(data, '\n\r')
if hend != -1:
return data[:hend]
else:
return ''
def getMessageRawBody(self, data):
hstart = string.find(data, '\n\r')
if hstart != -1:
return data[hstart+2:]
else:
return ''
def getEmailMessage(self, data):
"""
instanciate a email.Message from the source data
"""
parser = FeedParser()
parser.feed(data)
return parser.close()
def appendRecipient(self, recipientObject, dataList, recipientType):
"""
split dataList and add items to recipientObject
"""
for dest in dataList.split(','):
dest = dest.strip()
recipient = recipientObject.Add(dest.strip())
recipient.Type = recipientType
def Usage():
print """Usage pyspy.py port
Where:
port = Client SMTP Port number (ie 25)"""
sys.exit(1)
if __name__ == '__main__':
if len(sys.argv) != 2:
Usage()
port = int(sys.argv[1])
service = SMTPService()
server = smtps.SMTPServer(port)
print 'Python SMTP to MAPI Relay Ready. (c)2009 David SPORN\n\r'
server.serve(service)
# 2eme essais
Posté par David Sporn . En réponse au message Un prototype de relais SMTP vers MAPI en python. Évalué à 1.
elif cmd == "EHLO": return("502 Command not implemented", keep)Et voici le code de mon serveur. Celui-ci gère maintenant les destinataire (to, cc, bcc), par contre, pour les mails en multiple partie (pièces jointes, texte html etc) je ne fais que concaténer les partie dont le type de contenu contient "text/". Quoiqu'il en soit, c'est maintenant utilisable pour le besoin de base, l'envoi d'un message ou d'une réponse à plusieurs.