Basically, I have an email account I can access as POP3 or IMAP. I want to take all incoming emails, encrypt them, and then forward the encrypted version to my gmail account (so I can see the subject/notifications on my phone/gmail account; and possibly decrypt the message with a passphrase -- though this last step doesn't need to be implemented initially).

I probably could write a python script to do this, but using the proper linux tools seems like a better route. I have postfix (in a satelite configuration) already set up to send outgoing mail.

What's the easiest way to read POP3/IMAP on a linux box and get it to gpg encrypt the email's body and attachments (not subject headers) with my public key, and forward it to my gmail acct?

(For the record; its against work's policy (partially for compliance with US HIPAA law) for me to send unencrypted versions of my email to my phone; as there's the potential for someone to deliberately (or inadvertantly) email protected data to my phone. Work considers GPG to be secure.)


I just saw the other response and guess I never wrote up the solution I actually implemented. It turns out that python imaplib is straightforward and I wrote a very quick script. Barring a few changes (e.g., anonymizing my various USERNAMEs, EMAILPASSWORD, WORKDOMAINNAME, MYGPGKEYID). I also don't just send encrypted it; but prepend the subject with the username of the sender and put some of the header stuff before the GPG (in case I'm reading it on my phone and can't decrypt).


import imaplib
import email
from datetime import datetime,timedelta
import shelve
from subprocess import Popen, PIPE

def piped_call(command1, arg1_list, command2, arg2_list):
    if arg1_tuple = (a10, a11, a12); arg2_tuple is (a20, a21)    
    This executes "command1 a10 a11 a12 | command2 a20 a21 a22"
    if type(arg1_list) not in (list, tuple):
        arg1_list = [arg1_list,]
    if type(arg2_list) not in (list, tuple):
        arg2_list = [arg2_list,]
    p1 = Popen([command1,]+list(arg1_list), stdout=PIPE)
    p2 = Popen([command2,]+list(arg2_list), stdin=p1.stdout, stdout=PIPE)
    return p2.communicate()[0]

shlf = shelve.open('/home/USERNAME/mail/mail.shlf')
# This shelf (a persistent python dictionary written to file) has as its key 
# the IMAP message ids of all emails that have been processed by this script.
# Every time the script runs, I fetch all emails from the current day
# (except from midnight to 1am, where I fetch all emails since yesterday)
# and then send all emails that haven't been sent previously 
# by checking message ids against the python shelf.

M = imaplib.IMAP4_SSL(host='imap.WORKDOMAINNAME.com', port=993)
dt = datetime.now() - timedelta(0,5*60*60) 
# Only search for messages since the day of an hour earlier.  
# This way messages from yesterday don't get lost at midnight; as well as limiting the number of messages to process through to just todays.    
typ, uid_data = M.uid('search', None, '(SINCE %s)' % dt.strftime('%d-%b-%Y'))

for num in uid_data[0].split():
    typ, data = M.uid('fetch', num, '(RFC822)')
    e = email.message_from_string(data[0][1])
    print 'Message %s\n%s\n' % (num, e['subject'])
    if num not in shlf:
        sender_email = e['return-path']
        for s in ('<', '>', '@WORKDOMAINNAME.com'):
            sender_email = sender_email.replace(s,'')
        subject = "%s: %s" % (sender_email, e['Subject'])
        body = ("From: %s\n"
                "To: %s\n"
                "Cc: %s\n"
                "Subject: %s\n\n" % (e['From'], e['To'], e['Cc'], e['subject']))
        payload = e.get_payload()
        if type(payload) in (list, tuple):
            payload = str(payload[0])
            payload = str(payload)
        encrypted_payload = piped_call('echo', (payload,),
                                       'gpg', ('-e', '-a', '-r', 'MYGPGKEYID'))
        body += encrypted_payload
        piped_call('echo', (body,), 
                   'mail', ['USERNAME@gmail.com', '-s', subject])
        shlf[num] = datetime.now()


I then added the following lines to my crontab (the script above is named mail.py inside a directory called mail), so it will run every 5 minutes during the normal hours on weekdays (M-F 8-7pm) and less frequently at other hours. (crontab -e)

# Every 5 minutes, M-F from 8am - 7pm.    
*/5 8-19 * * 1-5  cd /home/USERNAME/mail && ./mail.py >> /home/USERNAME/mail/mail.log 2>&1
# Every 30 minutes, Sat&Sun from 8am-7pm
0,30 8-19 * * 6,7  cd /home/USERNAME/mail && ./mail.py >> /home/USERNAME/mail/mail.log 2>&1
# Every 30 minutes, M-F 8pm-2am; (no emails 2am-8am)
0,30 0-2,20-23 * * 1-5  cd /home/USERNAME/mail && ./mail.py >> /home/USERNAME/mail/mail.log 2>&1
# Every 60 minutes, Sat&Sun hours 8pm-2am; (no emails 2am-8am)
0 0-2,20-23 * * 6-7  cd /home/USERNAME/mail && ./mail.py >> /home/USERNAME/mail/mail.log 2>&1



  • 1
    Could you include some kind of explanation of how to set up fetchmail to do all this? Sep 14 '11 at 12:22
  • I don't think this would have done the trick. It seems to get and forward mail easily enough, but I don't see how I would insert the GPG encryption step before forwarding. Please correct me if I'm wrong.
    – dr jimbob
    Sep 14 '11 at 18:56
  • Hey dr jimbob, I assumed that once you had the mail locally you'd use your postfix installation to pipe/hook it through gpg and forward the result. Your script does the trick, but in your question you mentioned wanting to use tools found on linux. Glad you solved it!
    – rjp
    Sep 15 '11 at 5:00

I've had the need to forward root's mail encrypted too, and summarized my findings here : http://www-public.it-sudparis.eu/~berger_o/weblog/2006/01/20/secure-forwarding-of-roots-mail-through-gpg/

Maybe this can solve your needs too.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.