用于将消息从一个IMAP服务器移动到另一个IMAP服

时间:2011-08-11 16:42:44

标签: python email imap imaplib mail-server

我们的办公室使用2个IMAP服务器用于电子邮件,一个是传入服务器并保存最近的电子邮件,另一个是存档服务器。我们主要使用Outlook 2010,我们当前的流程是定期将发送的邮件从传入服务器拖到存档。

今天我被要求编写一个脚本,并定期(可能使用crontab)抓取所有已发送的消息并将其移动到存档。

我已经研究了一些SSL或telnet的例子来访问服务器并进行搜索。但是我不知道编写脚本的最佳方法,或者如何在IMAP环境中跨文件移动文件。

实现这一目标的最佳方法是什么?我更喜欢在舒适级别使用Python,但如果已经有另一种语言的现有解决方案,我可以处理它。


更新

好的,这是一些代码。目前它正好复制邮件,但它会在存档服务器上复制现有邮件。

import imaplib
import sys

#copy from
f_server = 'some.secret.ip.address'
f_username = 'j@example.com'
f_password = 'password'
f_box_name = 'Sent Messages'

#copy to
t_server = 'archive.server.i.p'
t_username = 'username'
t_password = 'password'
t_box_name = 'test'

To = imaplib.IMAP4(t_server) 
To.login(t_username, t_password)
print 'Logged into mail server'

From = imaplib.IMAP4(f_server)
From.login(f_username, f_password)
print 'Logged into archive'

From.select(f_box_name)  #open box which will have its contents copied
print 'Fetching messages...'
typ, data = From.search(None, 'ALL')  #get all messages in the box
msgs = data[0].split()

sys.stdout.write(" ".join(['Copying', str(len(msgs)), 'messages']))

for num in msgs: #iterate over each messages id number
    typ, data = From.fetch(num, '(RFC822)')
    sys.stdout.write('.')
    To.append(t_box_name, None, None, data[0][1]) #add a copy of the message to the archive box specified above

sys.stdout.write('\n')

try:
    From.close()
From.logout()

try:
    To.close()
To.logout()

有些消息来源:
Doug Hellman's Blog: imaplib - IMAP4 Client Library
Tyler Lesmann's Blog: Copying IMAP Mailboxes with Python and imaplib

我仍然需要:

  • 删除/删除实时服务器上的消息
  • 不复制副本(实际上这可以通过复制后删除原件来修复,但是......)
  • 错误捕获

更新2:

任何人都有关于如何在复制时不创建重复项的想法? (目前不包括删除原件的选项)我考虑过搜索文本,但实现了嵌套的回复可能会让它失效。

3 个答案:

答案 0 :(得分:3)

这是我最终使用的内容。我并不认为它是完美的,它使用msg_num而不是id的方式有点危险。但这是一个相当低的音量移动,可能是一个小时(在cron上)。

import imaplib

#copy from
from_server = {'server': '1.1.1.1',
               'username': 'j@example.com',
               'password': 'pass',
               'box_names': ['Sent', 'Sent Messages']}

#copy to
to_server = {'server': '2.2.2.2',
             'username': 'archive',
             'password': 'password',
             'box_name': 'Sent'}

def connect_server(server):
    conn = imaplib.IMAP4(server['server']) 
    conn.login(server['username'], server['password'])
    print 'Logged into mail server @ %s' % server['server']
    return conn

def disconnect_server(server_conn):
    out = server_conn.logout()

if __name__ == '__main__':
    From = connect_server(from_server)
    To = connect_server(to_server)

    for box in from_server['box_names']:
        box_select = From.select(box, readonly = False)  #open box which will have its contents copied
        print 'Fetching messages from \'%s\'...' % box
        resp, items = From.search(None, 'ALL')  #get all messages in the box
        msg_nums = items[0].split()
        print '%s messages to archive' % len(msg_nums)

        for msg_num in msg_nums:
            resp, data = From.fetch(msg_num, "(FLAGS INTERNALDATE BODY.PEEK[])") # get email
            message = data[0][1] 
            flags = imaplib.ParseFlags(data[0][0]) # get flags
            flag_str = " ".join(flags)
            date = imaplib.Time2Internaldate(imaplib.Internaldate2tuple(data[0][0])) #get date
            copy_result = To.append(to_server['box_name'], flag_str, date, message) # copy to archive

            if copy_result[0] == 'OK': 
                del_msg = From.store(msg_num, '+FLAGS', '\\Deleted') # mark for deletion

        ex = From.expunge() # delete marked
        print 'expunge status: %s' % ex[0]
        if not ex[1][0]: # result can be ['OK', [None]] if no messages need to be deleted
            print 'expunge count: 0'
        else:
            print 'expunge count: %s' % len(ex[1])

    disconnect_server(From)
    disconnect_server(To)

答案 1 :(得分:1)

我不确定您要处理的邮件数量是多少,但您可以从每个邮件中提取Message-ID并使用它来查明它是否重复。每次准备移动消息时,都会生成目标服务器上已有的ID列表,或者在归档时将它们添加到简单数据库中。

如果查找过于昂贵,您可以通过其他邮件属性(如Date)缩小范围,然后在不再需要时删除旧列表。

答案 2 :(得分:0)

大概太晚了,无法对OP有所帮助,但希望对现在跟随的人有用。

这看起来像一般要求。您可能不应该自定义任何编码。

使用配置为将所有内容的副本发送到存档以及将内容发送到IMAP服务器的MTA可能会更好。如果您难以设置,请考虑使用第三方服务,该服务将管理您的存档,并将邮件转发到您现有的邮件服务器。

如果您确实希望通过从IMAP复制来实现此目的,我建议您查看offlineimap

如果你真的想自己做,跟踪你已经看过的邮件的方法是使用Message-ID标题。