将邮件从一台 IMAP 服务器移动到另一台服务器的脚本

发布于 2024-11-29 06:30:04 字数 2152 浏览 1 评论 0原文

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

今天,我被要求考虑编写一个脚本,该脚本会定期(可能使用 crontab)抓取所有发送的消息并将它们移至存档。

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

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


更新:

好的,这是一些代码。目前,它可以很好地复制消息,但是,它会复制存档服务器上的现有消息。

import imaplib
import sys

#copy from
f_server = 'some.secret.ip.address'
f_username = '[email protected]'
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 的博客:imaplib - IMAP4 客户端库
泰勒·莱斯曼的博客:使用 Python 和 imaplib 复制 IMAP 邮箱

我仍然需要:

  • 删除/清除实时服务器上的邮件
  • 而不是复制重复项(实际上这将是通过在复制后删除原件来修复,但是...)
  • 错误捕获

更新2:

有人对如何在复制时不创建重复项有任何想法吗? (暂时不包括删除原件的选项)我考虑过搜索文本,但意识到嵌套回复可能会导致这种情况发生。

Our office uses 2 IMAP servers for e-mail, one is the incoming server and holds the recent e-mails and the other is an archive server. We mainly use Outlook 2010 and our current process is to periodically drag sent messages from the incoming server to the archive.

Today I was asked into looking into writing a script and that would periodically (probably using crontab) grab all sent messages and move them to archive.

I've looked into some example of SSL or telnet to access the server and poke around. However I don't know the best way to script this or how to move files cross server within the IMAP environment.

What's the best way to accomplish this? I'd prefer to use Python just from comfort level, but if there is already an existing solution in another language, I could deal with it.


Update:

Ok, here's some code. Currently It copies the messages just fine, however, it will duplicate exisiting messages on the archive server.

import imaplib
import sys

#copy from
f_server = 'some.secret.ip.address'
f_username = '[email protected]'
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()

Some sources:
Doug Hellman's Blog: imaplib - IMAP4 Client Library
Tyler Lesmann's Blog: Copying IMAP Mailboxes with Python and imaplib

I still need to:

  • delete/expunge messages on the live server
  • not copy duplicates (actually this would be fixed by deleting originals after copying, but...)
  • error trapping

Update 2:

Anyone have any ideas on how to not create duplicates when copying? (excluding the option of deleting originals, for now) I thought about searching text, but realized nested replies could throw that off.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

撩起发的微风 2024-12-06 06:30:04

这是我最终使用的。我并不是说它是完美的,它使用 msg_num 而不是 id 的方式有点冒险。但这是相当低的交易量,可能一个小时几个(在 cron 上)。

import imaplib

#copy from
from_server = {'server': '1.1.1.1',
               'username': '[email protected]',
               '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)

Here's what I ended up using. I don't claim that it's perfect, the way it uses msg_num and not id is a little risky. But this is fairly low volume moves, maybe a couple an hour (on cron).

import imaplib

#copy from
from_server = {'server': '1.1.1.1',
               'username': '[email protected]',
               '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)
夕嗳→ 2024-12-06 06:30:04

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

如果查找成本太高,您可以通过附加消息属性(例如 Date)来缩小范围,然后在不再需要旧列表时删除它们。

I'm not sure what volume of messages you're dealing with, but you could extract the Message-ID from each one and use that to find out if it's a duplicate. Either generate a list of IDs already on the target server each time you prepare to move messages, or add them to a simple database as they are archived.

You could narrow things down by an additional message property like Date if the lookups are too expensive, then drop the older lists when you no longer need them.

み青杉依旧 2024-12-06 06:30:04

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

这看起来像是一个通用要求。您可能不应该自定义任何代码。

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

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

如果您确实想自己执行此操作,则跟踪您已经看到的消息的方法是使用 Message-ID 标头。

Presumably too late to be helpful to the OP, but hopefully useful for anyone following along after now.

This looks like a generic requirement. You probably shouldn't be custom coding anything.

You would probably be better off using an MTA configured to send copies of everything to an archive as well as sending stuff to your IMAP server. If this is hard for you to set up, consider using a third party service, who would manage your archives, and forward mail on to your existing mail server.

If you really do want to do this by copying from IMAP, I'd suggest looking at offlineimap.

If you really do want to do it yourself, the way to track the messages you've already seen is by using the Message-ID header.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文