一个简单的 SMTP 服务器(Python)

问题描述 投票:0回答:9

您能否建议一个简单的 SMTP 服务器,它具有非常基本的 API(我的意思是非常基本的,读取、写入、删除电子邮件),可以在 Linux 机器上运行? 我只需要将电子邮件的核心内容转换为 XML 格式,然后将其通过 FTP 传输到另一台机器即可。

python smtp
9个回答
55
投票

看看这个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
将电子邮件转储到文件。


28
投票

发送电子邮件确实需要做两件事:

对于阅读,有两个选项,具体取决于您从哪个服务器阅读电子邮件。

    对于 POP 电子邮件服务器 - 您可以使用 poplib python 库:
  • http://docs.python.org/library/poplib.html
  • 对于 IMAP 电子邮件服务器 - 您可以使用 imaplib python 库:
  • http://docs.python.org/library/imaplib.html

12
投票
为了让 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()
    

6
投票
更现代的方法是使用

aiosmtpd 库(文档位于此处)。

您可以在这里找到一个很好的示例:

https://aiosmtpd.readthedocs.io/en/latest/controller.html


4
投票
我成功使用的两个 python smtp 服务器是:

    Twisted 的
  1. 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()
    

2
投票
这些都是很好的开始示例。

smtpd – 示例 SMTP 服务器

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

smtplib – 简单邮件传输协议客户端

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


2
投票
我还想用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
 的请求。请注意,要实际发送电子邮件(或短信),您需要跳过此处详细介绍的其他环节:
https://blog.codinghorror.com/so-youd-like-to-send-some-email-through-代码/.


1
投票

Python SMTP 服务器

该模块提供了几个类来实现 SMTP 服务器。一个是一个 通用的无所事事的实现,可以被覆盖,而 另外两个提供特定的邮件发送策略。


0
投票
如果你想快速测试 Django 的

send_mail 和上面 hasen 的答案:

# 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 的例子中可以很好地工作。

© www.soinside.com 2019 - 2024. All rights reserved.