Now the main difficulty is that the recieved date isn't actually stored in the message header as all the other message meta-data, such as subject, sender, reciever etc is. It's stored by the IMAP/POP server, usually as the timestamp of the file on the mail server. Now if (like me) the only access to your mail server is via IMAP/POP3, then it's impossible to directly change the timestamp.
The IMAP protocol does allow you to query the received date - it's called the 'Internal Date'. Unfortuneately, it's a read-only field that can't be modified after a message has been created... However, if you store a new copy of each message and upon creation set it's 'Internal Date' (received date), then you can indeed fix the date, and that is exactly what the python script below does:
download fix_date.py
#!/usr/bin/python
# fix_date.py - corrects the received date in IMAP folders.
# Description:
# When moving mail between IMAP servers, the received date can become
# reset to the date when the message was added to the new server. This
# script attempts to fix this by setting the received date to the date the
# message was sent.
# Usage:
# Set the 5 variables below to suit your setup, and then run the script.
# If you run the script with the argument '--list', then it will just list
# all the mailboxes on the server. Useful if you don't know the exact name
# of the mailboxes.
# Notes:
# Due to the may IMAP works, you cannot change the recieved date for an
# existing message. To get round this, fix_date.py makes a new copy of the
# message in a different folder. As it has to copy each message, process
# can take some time!
# With some additional work the date could be set to the last received hop
# in the mail's delivery, but I didn't need that accuracy.
import imaplib
import email.Utils
import sys
# Change the following 5 lines as applicable:
source = "INBOX.Source" # The source folder to read the messages to fix.
dest = "INBOX.Dest" # The destination folder to save to new copy.
server = "imap.example.com" # IMAP server address
user = "user" # Username
passwd = "password" # Password
M = imaplib.IMAP4(server)
M.login(user, passwd)
if len(sys.argv) == 2 and sys.argv[1] == '--list':
print "List of mailboxes available on server:"
for mbox in M.list()[1]:
print mbox.split('"."')[1]
else:
M.select(source)
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, date = M.fetch(num, '(BODY[HEADER.FIELDS (DATE)])')
typ, body = M.fetch(num, '(RFC822)')
date_str = date[0][1][6:].strip()
datetime = email.Utils.parsedate(date_str)
print "Message (" + num + "), date:" + date_str
M.append(dest, None, imaplib.Time2Internaldate(datetime), body[0][1])
#print body[0][1]
M.logout()
(I'm not usually a Python person, but my initial attempt to do this is Perl failed as the perl Mail::IMAP module would not correctly read back the whole message including header).
« hide more
Benson Wong has accomplished the same task using a shell script. If you have local access to your IMAP server, it's probably much quicker than my method.