【问题标题】:Trigger script upon email receipt收到电子邮件时触发脚本
【发布时间】:2014-05-01 06:44:42
【问题描述】:

每次我的网络服务器在特定帐户上收到电子邮件时,我都需要触发 python 脚本。我还需要将电子邮件作为参数传递给脚本。我的网络服务器正在使用 Dovecot。我该怎么做?

【问题讨论】:

    标签: python email dovecot


    【解决方案1】:

    我建议您查看Twisted,特别是它的IMAPPOP 协议和客户端模块。

    举个例子:

    #!/usr/bin/env python
    
    # Copyright (c) Twisted Matrix Laboratories.
    # See LICENSE for details.
    
    
    """
    Simple IMAP4 client which displays the subjects of all messages in a
    particular mailbox.
    """
    import sys
    
    from twisted.internet import protocol
    from twisted.internet import ssl
    from twisted.internet import defer
    from twisted.internet import stdio
    from twisted.mail import imap4
    from twisted.protocols import basic
    from twisted.python import util
    from twisted.python import log 
    
    class TrivialPrompter(basic.LineReceiver):
        from os import linesep as delimiter
    
        promptDeferred = None
    
        def prompt(self, msg):
            assert self.promptDeferred is None
            self.display(msg)
            self.promptDeferred = defer.Deferred()
            return self.promptDeferred
    
        def display(self, msg):
            self.transport.write(msg)
    
        def lineReceived(self, line):
            if self.promptDeferred is None:
                return
            d, self.promptDeferred = self.promptDeferred, None
            d.callback(line)
    
    class SimpleIMAP4Client(imap4.IMAP4Client):
        """
        A client with callbacks for greeting messages from an IMAP server.
        """
        greetDeferred = None
    
        def serverGreeting(self, caps):
            self.serverCapabilities = caps
            if self.greetDeferred is not None:
                d, self.greetDeferred = self.greetDeferred, None
                d.callback(self)
    
    class SimpleIMAP4ClientFactory(protocol.ClientFactory):
        usedUp = False
    
        protocol = SimpleIMAP4Client
    
        def __init__(self, username, onConn):
            self.ctx = ssl.ClientContextFactory()
    
            self.username = username
            self.onConn = onConn
    
        def buildProtocol(self, addr):
            """
            Initiate the protocol instance. Since we are building a simple IMAP
            client, we don't bother checking what capabilities the server has. We
            just add all the authenticators twisted.mail has.  Note: Gmail no
            longer uses any of the methods below, it's been using XOAUTH since
            2010.
            """
            assert not self.usedUp
            self.usedUp = True
    
            p = self.protocol(self.ctx)
            p.factory = self
            p.greetDeferred = self.onConn
    
            p.registerAuthenticator(imap4.PLAINAuthenticator(self.username))
            p.registerAuthenticator(imap4.LOGINAuthenticator(self.username))
            p.registerAuthenticator(
                    imap4.CramMD5ClientAuthenticator(self.username))
    
            return p
    
        def clientConnectionFailed(self, connector, reason):
            d, self.onConn = self.onConn, None
            d.errback(reason)
    
    
    
    def cbServerGreeting(proto, username, password):
        """
        Initial callback - invoked after the server sends us its greet message.
        """
        # Hook up stdio
        tp = TrivialPrompter()
        stdio.StandardIO(tp)
    
        # And make it easily accessible
        proto.prompt = tp.prompt
        proto.display = tp.display
    
        # Try to authenticate securely
        return proto.authenticate(password
            ).addCallback(cbAuthentication, proto
            ).addErrback(ebAuthentication, proto, username, password
            )
    
    def ebConnection(reason):
        """
        Fallback error-handler. If anything goes wrong, log it and quit.
        """
        log.startLogging(sys.stdout)
        log.err(reason)
        return reason
    
    def cbAuthentication(result, proto):
        """
        Callback after authentication has succeeded.
    
        Lists a bunch of mailboxes.
        """
        return proto.list("", "*"
            ).addCallback(cbMailboxList, proto
            )
    
    
    def ebAuthentication(failure, proto, username, password):
        """
        Errback invoked when authentication fails.
    
        If it failed because no SASL mechanisms match, offer the user the choice
        of logging in insecurely.
    
        If you are trying to connect to your Gmail account, you will be here!
        """
        failure.trap(imap4.NoSupportedAuthentication)
        return proto.prompt(
            "No secure authentication available. Login insecurely? (y/N) "
            ).addCallback(cbInsecureLogin, proto, username, password
            )
    
    
    def cbInsecureLogin(result, proto, username, password):
        """
        Callback for "insecure-login" prompt.
        """
        if result.lower() == "y":
            # If they said yes, do it.
            return proto.login(username, password
                ).addCallback(cbAuthentication, proto
                )
        return defer.fail(Exception("Login failed for security reasons."))
    
    
    def cbMailboxList(result, proto):
        """
        Callback invoked when a list of mailboxes has been retrieved.
        """
        result = [e[2] for e in result]
        s = '\n'.join(['%d. %s' % (n + 1, m) for (n, m) in zip(range(len(result)), result)])
        if not s:
            return defer.fail(Exception("No mailboxes exist on server!"))
        return proto.prompt(s + "\nWhich mailbox? [1] "
            ).addCallback(cbPickMailbox, proto, result
            )
    
    
    def cbPickMailbox(result, proto, mboxes):
        """
        When the user selects a mailbox, "examine" it.
        """
        mbox = mboxes[int(result or '1') - 1]
        return proto.examine(mbox
            ).addCallback(cbExamineMbox, proto
            )
    
    
    def cbExamineMbox(result, proto):
        """
        Callback invoked when examine command completes.
    
        Retrieve the subject header of every message in the mailbox.
        """
        return proto.fetchSpecific('1:*',
                                   headerType='HEADER.FIELDS',
                                   headerArgs=['SUBJECT'],
            ).addCallback(cbFetch, proto
            )
    
    
    def cbFetch(result, proto):
        """
        Finally, display headers.
        """
        if result:
            keys = result.keys()
            keys.sort()
            for k in keys:
                proto.display('%s %s' % (k, result[k][0][2]))
        else:
            print "Hey, an empty mailbox!"
    
        return proto.logout()
    
    
    def cbClose(result):
        """
        Close the connection when we finish everything.
        """
        from twisted.internet import reactor
        reactor.stop()
    
    
    def main():
        hostname = raw_input('IMAP4 Server Hostname: ')
        port = raw_input('IMAP4 Server Port (the default is 143, 993 uses SSL): ')
        username = raw_input('IMAP4 Username: ')
        password = util.getPassword('IMAP4 Password: ')
    
        onConn = defer.Deferred(
            ).addCallback(cbServerGreeting, username, password
            ).addErrback(ebConnection
            ).addBoth(cbClose)
    
        factory = SimpleIMAP4ClientFactory(username, onConn)
    
        from twisted.internet import reactor
        if port == '993':
            reactor.connectSSL(hostname, int(port), factory, ssl.ClientContextFactory())
        else:
            if not port:
                port = 143
            reactor.connectTCP(hostname, int(port), factory)
        reactor.run()
    
    
    if __name__ == '__main__':
        main()
    

    当您从您正在检查的 IMAP 文件夹中检测到一封新电子邮件时,您只需在子流程中调用您的 Python 脚本...在这里您还可以使用 Twisted 的流程处理作为记录在这里:https://twistedmatrix.com/documents/13.0.0/core/howto/process.html

    祝你好运!

    【讨论】:

      【解决方案2】:

      如果 IMAP 服务器支持 IDLE 命令,它可能会通知您有关新消息的信息。如果它不支持它,那么您可以使用 stdlib (code example to retrieve messages from a time period) 中的 imaplib 定期轮询收件箱。

      imaplib 不支持 IDLE 命令,但可以轻松添加,例如 imapidle:

      from imapidle import imaplib
      
      m = imaplib.IMAP4_SSL('imap.gmail.com')
      m.login('robert', 'pa55w0rd')
      m.select()
      for uid, msg in m.idle(): # yield new messages
          print msg
      

      另见How do I enable push-notification for IMAP (Gmail) using Python imaplib?

      【讨论】:

        猜你喜欢
        • 2018-10-06
        • 2010-10-10
        • 2010-09-23
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-02
        • 1970-01-01
        相关资源
        最近更新 更多