O'Reilly Hacks
oreilly.comO'Reilly NetworkSafari BookshelfConferences Sign In/My Account | View Cart   
Book List Learning Lab PDFs O'Reilly Gear Newsletters Press Room Jobs  


Proxy mail through ssh without port forwarding.
In my situation, I am behind a firewall which blocks all SMTP requests, so that I cannot send any mail from my mail client, mutt. However, I have access through ssh to a server which is connected to an SMTP server, andI describe how to enable communication to that server without port forwarding.

Contributed by:
[01/24/06 | Discuss (1) | Link to this hack]

I am behind a very restrictive firewall which blocks all my SMTP requests in my network, in a bid to prevent viruses from spreading due to a notorious mail client. On top of that, the only ssh server I have access to can connect to an SMTP server, but port forwarding has been blocked. So, this hack is to use the ssh server as a mail relay without port forwarding for mail clients like Mutt, KMail.

The concept used is simple: first, enable automatic ssh logging. Then, open a pipe to the ssh server using pexpect, and then code the SMTP server text like this:

import pexpect, sys                                                                                            
import email                                                                                                   
from email.Utils import getaddresses                                                                           
SSHSERV = "sshserv"                                                                                  
SMTPSERV = "smtpserv"                                                                                          
if __name__ == "__main__":                                                                                     
    s = sys.stdin.read()                                                                                       
    msg = email.message_from_string(s)                                                                         
    tos = msg.get_all('to', [])                                                                                
    ccs = msg.get_all('cc', [])                                                                                
    bccs = msg.get_all('bcc', [])                                                                              
    resent_tos = msg.get_all('resent-to', [])                                                                  
    resent_ccs = msg.get_all('resent-cc', [])                                                                  
    all_recipients = getaddresses(tos + ccs + bccs + resent_tos + resent_ccs)                                  
    from_addr = email.Utils.parseaddr(msg['From'])[1]                                                          
    if msg.has_key('Resent-From'):                                                                             
        from_addr = email.Utils.parseaddr(msg['Resent-From'])[1]                                               
    child = pexpect.spawn ('ssh %s telnet %s 25' % (SSHSERV, SMTPSERV))                                        
    child.expect ('220 .*')                                                                                    
    import socket                                                                                              
    child.sendline ('ehlo %s' % socket.getfqdn())                                                                      
    child.expect ('250 8BITMIME')                                                                              
    child.sendline ('MAIL FROM: <%s>' % from_addr)                                                             
    child.expect ('250 Ok.*')                                                                                  
    for rcpt in all_recipients:                                                                                
        if len(rcpt[1]) < 1 or rcpt[1] == "<>":                                                                
        child.sendline ('RCPT TO: <%s>' % rcpt[1])                                                             
        child.expect ('250 Ok.*')                                                                              
    child.send(s + "\n.\n")                                                                                    
    child.expect ('250 Ok.*')                                                                                  

Adapt the SSHSERV and SMTPSERV to your needs. Now, set this to be the "sendmail" program of your mail client, like Mutt or KMail, and enjoy!

The concept can be extended to write a mail proxy server as well, which can be used to forward requests from mail from other "network only" clients like Netscape Mail.

O'Reilly Home | Privacy Policy

© 2007 O'Reilly Media, Inc.
Website: | Customer Service: | Book issues:

All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.