web-dev-qa-db-ja.com

シンプルなSMTPサーバー(Python)

Linuxボックスで実行できる非常に基本的なAPI(つまり、メールの読み取り、書き込み、削除)を備えたシンプルなSMTPサーバーを提案していただけませんか?メールの要点をXML形式に変換し、それを別のマシンにFTPで転送するだけです。

27
fixxxer

これを見てください SMTPシンクサーバー

from __future__ import print_function
from datetime import datetime
import asyncore
from smtpd import SMTPServer

class EmlServer(SMTPServer):
    no = 0
    def process_message(self, peer, mailfrom, rcpttos, data):
        filename = '%s-%d.eml' % (datetime.now().strftime('%Y%m%d%H%M%S'),
                self.no)
        f = open(filename, 'w')
        f.write(data)
        f.close
        print('%s saved.' % filename)
        self.no += 1


def run():
    # start the smtp server on localhost:1025
    foo = EmlServer(('localhost', 1025), None)
    try:
        asyncore.loop()
    except KeyboardInterrupt:
        pass


if __name__ == '__main__':
    run()

それは使用しています smtpd.SMTPServerメールをファイルにダンプします。

41
hasen

メールを送信するには、実際に2つのことが必要です。

  • SMTPサーバー-これは Python SMTPサーバー にすることも、GMailまたはISPのサーバーを使用することもできます。おそらく、自分で実行する必要はありません。
  • SMTPライブラリ-電子メール要求をSMTPサーバーに送信するもの。 Pythonは、あなたのためにそれを行うことができるsmtplibと呼ばれるライブラリに同梱されています。それを使用する方法に関するたくさんの情報がここにあります: http://docs.python.org/library /smtplib.html

読み取りには、メールをどのサーバーから読み取っているかによって2つのオプションがあります。

21
Chris Dail

私が成功に使用した2つのpython smtpサーバーは次のとおりです。

  1. Twistedの Mail -SMTP、IMAPなどの非常に柔軟なメールライブラリ.
  2. python-slimta -完全なMTA(smtpリレー/転送サーバー)

Twistedの例を以下に示します

# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.

# You can run this module directly with:
#    twistd -ny emailserver.tac

"""
A toy email server.
"""
from __future__ import print_function

from zope.interface import implementer

from twisted.internet import defer
from twisted.mail import smtp
from twisted.mail.imap4 import LOGINCredentials, PLAINCredentials

from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse
from twisted.cred.portal import IRealm
from twisted.cred.portal import Portal



@implementer(smtp.IMessageDelivery)
class ConsoleMessageDelivery:
    def receivedHeader(self, helo, Origin, recipients):
        return "Received: ConsoleMessageDelivery"


    def validateFrom(self, helo, Origin):
        # All addresses are accepted
        return Origin


    def validateTo(self, user):
        # Only messages directed to the "console" user are accepted.
        if user.dest.local == "console":
            return lambda: ConsoleMessage()
        raise smtp.SMTPBadRcpt(user)



@implementer(smtp.iMessage)
class ConsoleMessage:
    def __init__(self):
        self.lines = []


    def lineReceived(self, line):
        self.lines.append(line)


    def eomReceived(self):
        print("New message received:")
        print("\n".join(self.lines))
        self.lines = None
        return defer.succeed(None)


    def connectionLost(self):
        # There was an error, throw away the stored lines
        self.lines = None



class ConsoleSMTPFactory(smtp.SMTPFactory):
    protocol = smtp.ESMTP

    def __init__(self, *a, **kw):
        smtp.SMTPFactory.__init__(self, *a, **kw)
        self.delivery = ConsoleMessageDelivery()


    def buildProtocol(self, addr):
        p = smtp.SMTPFactory.buildProtocol(self, addr)
        p.delivery = self.delivery
        p.challengers = {"LOGIN": LOGINCredentials, "PLAIN": PLAINCredentials}
        return p



@implementer(IRealm)
class SimpleRealm:
    def requestAvatar(self, avatarId, mind, *interfaces):
        if smtp.IMessageDelivery in interfaces:
            return smtp.IMessageDelivery, ConsoleMessageDelivery(), lambda: None
        raise NotImplementedError()



def main():
    from twisted.application import internet
    from twisted.application import service    

    portal = Portal(SimpleRealm())
    checker = InMemoryUsernamePasswordDatabaseDontUse()
    checker.addUser("guest", "password")
    portal.registerChecker(checker)

    a = service.Application("Console SMTP Server")
    internet.TCPServer(2500, ConsoleSMTPFactory(portal)).setServiceParent(a)

    return a

application = main()
4
frmdstryr

これらは、最初の良い例です。

smtpd –サンプルSMTPサーバー

http://pymotw.com/2/smtpd/index.html

smtplib – Simple Mail Transfer Protocolクライアント

http://pymotw.com/2/smtplib/index.html

2
The Demz

より最近のアプローチは、 aiosmtpd ライブラリー(使用可能なドキュメント ここ )を使用することです。

ここで良い例を見つけることができます: https://aiosmtpd.readthedocs.io/en/latest/aiosmtpd/docs/controller.html

2
Floyd

Python SMTPサーバー があります。

このモジュールは、SMTPサーバーを実装するためのいくつかのクラスを提供します。 1つは一般的な何もしない実装で、オーバーライドできますが、他の2つは特定のメール送信戦略を提供します。

1
zoli2k

また、Pythonでsmtpサーバーを起動して、Pythonでメールを送信したいと思っていました。これをすべてFlask Webアプリケーションで単一のプロセスで実行したかったので、つまり、smtpサーバーは非ブロッキングである必要があります。これが最終的に[ Gist ]になった解決策です:

app.py

from flask import Flask, render_template
from smtp_client import send_email
from smtp_server import SMTPServer

app = Flask(__name__)

@app.route('/send_email')
def email():
  server = SMTPServer()
  server.start()
  try:
    send_email()
  finally:
    server.stop()
  return 'OK'

@app.route('/')
def index():
  return 'Woohoo'

if __name__ == '__main__':
  app.run(debug=True, Host='0.0.0.0')

smtp_server.py

# smtp_server.py
import smtpd
import asyncore
import threading

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

class SMTPServer():
  def __init__(self):
    self.port = 1025

  def start(self):
    '''Start listening on self.port'''
    # create an instance of the SMTP server, derived from  asyncore.dispatcher
    self.smtp = CustomSMTPServer(('0.0.0.0', self.port), None)
    # start the asyncore loop, listening for SMTP connection, within a thread
    # timeout parameter is important, otherwise code will block 30 seconds
    # after the smtp channel has been closed
    kwargs = {'timeout':1, 'use_poll': True}
    self.thread = threading.Thread(target=asyncore.loop, kwargs=kwargs)
    self.thread.start()

  def stop(self):
    '''Stop listening to self.port'''
    # close the SMTPserver to ensure no channels connect to asyncore
    self.smtp.close()
    # now it is safe to wait for asyncore.loop() to exit
    self.thread.join()

  # check for emails in a non-blocking way
  def get(self):
    '''Return all emails received so far'''
    return self.smtp.emails

if __name__ == '__main__':
  server = CustomSMTPServer(('0.0.0.0', 1025), None)
  asyncore.loop()

smtp_client.py

import smtplib
import email.utils
from email.mime.text import MIMEText

def send_email():
  sender='[email protected]'
  recipient='[email protected]'

  msg = MIMEText('This is the body of the message.')
  msg['To'] = email.utils.formataddr(('Recipient', recipient))
  msg['From'] = email.utils.formataddr(('Author', '[email protected]'))
  msg['Subject'] = 'Simple test message'

  client = smtplib.SMTP('127.0.0.1', 1025)
  client.set_debuglevel(True) # show communication with the server
  try:
    client.sendmail('[email protected]', [recipient], msg.as_string())
  finally:
    client.quit()

次に、python app.pyを使用してサーバーを起動し、別のリクエストで/send_emailを使用したcurl localhost:5000/send_emailへのリクエストをシミュレートします。メール(またはSMS)を実際に送信するには、ここで説明されている他のフープをジャンプする必要があることに注意してください: https://blog.codinghorror.com/so-youd-like-to- send-some-email-through-code /

0
duhaime

HasenのスクリプトをPython 3で動作させるには、少し微調整する必要がありました。

from datetime import datetime
import asyncore
from smtpd import SMTPServer

class EmlServer(SMTPServer):
    no = 0
    def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
        filename = '%s-%d.eml' % (datetime.now().strftime('%Y%m%d%H%M%S'),
            self.no)
        print(filename)
        f = open(filename, 'wb')
        f.write(data)
        f.close
        print('%s saved.' % filename)
        self.no += 1

def run():
    EmlServer(('localhost', 25), None)
    try:
        asyncore.loop()
    except KeyboardInterrupt:
        pass

if __name__ == '__main__':
    run()
0
Protector one

Djangoの send_mailhasen's ですばやくテストしたい場合:

# Skip lines 3 and 4 if not using virtualenv.
# At command Prompt

mkdir Django1
cd Django1
virtualenv venv
source venv/bin/activate
pip install Django==1.11
Django-admin startproject Django1 .

# run the Django Shell

python manage.py Shell

# paste into Shell following:

from Django.core.mail import send_mail

send_mail(
    'Subject here',
    'Here is the message.',
    '[email protected]',
    ['[email protected]'],
    fail_silently=False,
)
# This should write an email like the following:

Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Subject here
From: [email protected]
To: [email protected]
Date: Wed, 02 May 2018 02:12:09 -0000
Message-ID: <20180502021209.32641.51865@i1022>

Here is the message.

Send_mail関数に有効な値を含める必要はありません。上記の値はhasenの例で問題なく動作します。

0
small mammal