将消息从一个 IMAP 服务器移动到另一个的脚本
Posted
技术标签:
【中文标题】将消息从一个 IMAP 服务器移动到另一个的脚本【英文标题】:Script to move messages from one IMAP server to another 【发布时间】:2011-10-25 04:11:28 【问题描述】:我们的办公室使用两台 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 LibraryTyler Lesmann's Blog: Copying IMAP Mailboxes with Python and imaplib
我还需要:
删除/清除实时服务器上的消息 不复制副本(实际上这可以通过在复制后删除原件来解决,但是...) 错误捕获更新 2:
有人对如何在复制时不创建重复项有任何想法吗? (暂时不包括删除原件的选项)我考虑过搜索文本,但意识到嵌套回复可能会解决这个问题。
【问题讨论】:
rsync 是从一个系统复制到另一个系统的选项吗? 【参考方案1】:想对 OP 有所帮助可能为时已晚,但希望对以后跟进的任何人都有用。
这看起来像是一个通用要求。您可能不应该自定义编码任何东西。
您最好使用配置为将所有内容的副本发送到存档以及将内容发送到 IMAP 服务器的 MTA。如果这对您来说很难设置,请考虑使用第三方服务,该服务将管理您的档案,并将邮件转发到您现有的邮件服务器。
如果您确实想通过从 IMAP 复制来做到这一点,我建议您查看 offlineimap。
如果你真的想自己做,跟踪你已经看到的消息的方法是使用 Message-ID 标头。
【讨论】:
【参考方案2】:这是我最终使用的。我并不声称它是完美的,它使用 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)
【讨论】:
【参考方案3】:我不确定您要处理的消息量是多少,但您可以从每条消息中提取Message-ID
并使用它来确定它是否是重复的。每次准备移动消息时,生成目标服务器上已有的 ID 列表,或者在归档时将它们添加到简单的数据库中。
如果查找成本太高,您可以通过附加消息属性(例如 Date
)来缩小范围,然后在不再需要旧列表时删除它们。
【讨论】:
以上是关于将消息从一个 IMAP 服务器移动到另一个的脚本的主要内容,如果未能解决你的问题,请参考以下文章
使用 IMAP 发送邮件:如何检测邮件已从一个文件夹移动到另一个文件夹?
使用 Powershell 将 MSMQ 消息从一个队列移动到另一个队列
PHP imap_open(),OpenSSL,并且没有密码