Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Antispam SMTP non bloquant

+4 votes

Je teste le module smtpd pour créer un anti-spam SMTP en Python 3. J'ai mis dans process_message() le code d'analyse des emails (et plus tard de forward) mais asyncore bloque la réception des autres emails. Si j'ai bien compris c'est un problème de I/O bloquant.

Quelle serait la solution ?

1) Twisted ou Tornado ?
J'ai l'impression que je n'aurais pas accès à toutes les données SMTP (voir lien de Twisted).

2) Asyncio ?
L'implémentation aiosmtpd ne me semble pas suffisament mature. Je ne crois pas que cela résoudra mon problème de I/O bloquant.

3) Ajouter multiprocessing comme dans secure-smtpd?
J'imagine que c'est la plus performante des 3 solutions mais elle me parait compliquée. Je n'ai pas trouvé d'exemple en Python 3.

4) Autre idée ?

Mon code est inspiré de cet exemple : https://gist.github.com/poke/6091a355db13c60153e9

demandé 29-Oct-2015 par dsy73 (190 points)

Au final j'ai choisi une implémentation de serveur SMTP basée sur Tornado. J'avais déjà créé un serveur de monitoring avec Tornado et il est toujours aussi plaisant à utiliser.

Dommage que Tornado soit si peu connu...

2 Réponses

+1 vote

En principe, asyncore est justement fait pour gérer les IO bloquants, comme son nom l'indique (de mémoire, c'est à base de select). Je ne sais pas pourquoi ton code bloque, a priori tu as introduit des IO là où ce n'est pas prévu, mais je ne vois pas où. Il serait utile de vérifier quelle IO bloque (si c'est bien le cas).

Quant à aiosmtpd, par définition si ton code lui aussi utilise des IO asynchrones, tu ne peux pas non plus avoir d'IO bloquant.

Sinon, ça me parait bizarre que tu aies à redéfinir handle_accepted, c'est sans doute inutile.

répondu 29-Oct-2015 par yoch (2,062 points)
edité 29-Oct-2015 par yoch

En principe, asyncore est justement fait pour gérer les IO bloquants,
comme son nom l'indique (de mémoire, c'est à base de select).

Désolé, il manque du code dans mon exemple : le renvoi de l'email vers le serveur SMTP principal, c'est ce code dans process_message() qui est lent. En effet je dois attendre que le serveur SMTP principal réponde.
Comme c'est un antispam, il y aura aussi du CPU bound à cause des règles de filtrage.

Je ne sais pas pourquoi ton code bloque, a priori tu as introduit des
IO là où ce n'est pas prévu, mais je ne vois pas où. Il serait utile
de vérifier quelle IO bloque (si c'est bien le cas).

J'ai mis le code bloquant dans processmessage() en prenant exemple sur le code de smtpd. Notamment la classe PureProxy qui appelle _deliver() dans processmessage()

Sinon, ça me parait bizarre que tu aies à redéfinir handle_accepted,
c'est sans doute inutile.

J'ai redéfini handleaccepted() pour accéder aux méthodes smtpMAIL, smtp_RCPT, etc en passant par le SMTPChannel. J'ai ainsi un contrôle complet sur les données qui arrivent sur le serveur SMTP, je peux filtrer les spams.

Je vois mieux.

Il semble bien que le code de PureProxy soit effectivement bloquant, c'est curieux.

La solution la plus simple à mon avis, si tu as des IO bloquantes / du CPU bound au niveau de process_message(), est de passer par des threads pour le traitement en question. D'ailleurs, n'importe quelle solution à base d'asynchrone ne conviendra pas pour le coté CPU bound.

Pour handle_accepted(), ton code est strictement identique au code dans la classe mère (à un print près), c'est pour ça que je n'en vois pas l'utilité.

0 votes

Asyncio, twisted ou tornado résoudrons tous ton problème d'IO bloquant à la condition :

  • de convertir ton programme pour fonctionner dans une event loop;
  • d'identifier quelle partie du programme bloque;
  • de remplacer cette partie par du code utiliser asyncio/tornado/twisted.

Une autre manière de faire est d'utiliser une pool multithreading: http://sebastianraschka.com/Articles/2014_multiprocessing_intro.html

répondu 30-Oct-2015 par Sam (4,974 points)
...