A few times recently I’ve wanted to be able to turn an e-mail into a voice call. This would be especially handy for emergency server monitoring and notification.
Here is my first attempt. It’s also my first attempt at writing something in Python so you definitely use at your own risk!
There is room for improvement as there is no validation on any of the fields extracted from the e-mail.
It also assumes that these components are already in place –
- Asterisk (with Astersk Manager Interface)
- E-mail server (I’m using Postfix)
- Ceptral text-to-speech (www.cepstral.com) – installed in /opt/swift/bin
- Python (I’m using v2.4.3)
First we need to pipe the incoming e-mail to our Python script. For this I added a line to /etc/aliases –
emailspeak: "|/usr/local/bin/emailspeak.py"
and ran newaliases –
newaliases
Now for the script which is called ‘/usr/local/bin/emailspeak.py’
You will need to change at least the USER, SECRET and TRUNK settings at the top of the script to match you Asterisk setup.
#!/usr/bin/env python # emailspeak.py by sysadminman - http://sysadminman.net # v1.0 13/2/10 # Import libs we need import sys, time, email, email.Message, email.Errors, email.Utils, smtplib, os, socket, random from datetime import date from email.Iterators import typed_subpart_iterator from time import sleep # Asterisk Manager connection details HOST = '127.0.0.1' PORT = 5038 # Asterisk Manager username and password USER = 'manageruser' SECRET = 'managerpass' # Set the name of the SIP trunk to use for outbound calls TRUNK = 'trunkforcalls' # Generate a random number as a string. We'll use this for file names later on callnum = str(random.randint(1, 100000000)) # Taken from here, with thanks - http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with-python/ def get_charset(message, default="ascii"): """Get the message charset""" if message.get_content_charset(): return message.get_content_charset() if message.get_charset(): return message.get_charset() return default # Taken from here, with thanks - http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual-email-with-python/ def get_body(message): """Get the body of the email message""" if message.is_multipart(): #get the plain text version only text_parts = [part for part in typed_subpart_iterator(message, 'text', 'plain')] body = [] for part in text_parts: charset = get_charset(part, get_charset(message)) body.append(unicode(part.get_payload(decode=True), charset, "replace")) return u"\n".join(body).strip() else: # if it is not multipart, the payload will be a string # representing the message body body = unicode(message.get_payload(decode=True), get_charset(message), "replace") return body.strip() # Read the e-mail message that has been piped to us by Postfix raw_msg = sys.stdin.read() emailmsg = email.message_from_string(raw_msg) # Extract database Fields from mail msgfrom = emailmsg['From'] msgto = emailmsg['To'] msgsubj = emailmsg['Subject'] msgbody = get_body(emailmsg) # Write a log file in /tmp with a record of the e-mails currtime = date.today().strftime("%B %d, %Y") logfile = open('/tmp/email2voice.log', 'a') logfile.write(currtime + "\n") logfile.write("Call Number: " + callnum + "\n") logfile.write("From: " + msgfrom + "\n") logfile.write("To: " + msgto + "\n") logfile.write("Subject: " + msgsubj + "\n") logfile.write("Body: " + msgbody + "\n\n") logfile.close() # Convert the body of the text to a wav file swiftcommand = "/opt/swift/bin/swift -n Millie-8kHz -o /tmp/" + callnum + ".wav '" + msgbody + "'" os.system(swiftcommand) # We need to allow Asterisk permission to read the wav file chmodcommand = "chmod 777 /tmp/" + callnum + ".wav" os.system(chmodcommand) # Set the number to be dailed as the subject of the e-mail OUTBOUND = msgsubj # Send the call details to the Asteirsk Manager Interface s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) sleep(3) s.send('Action: login\r\n') s.send('Username: ' + USER + '\r\n') s.send('Secret: ' + SECRET + '\r\n\r\n') sleep(3) s.send('Events: off\r\n\r\n') sleep(3) s.send('Action: originate\r\n') s.send('Channel: Sip/' + TRUNK + '/' + OUTBOUND + '\r\n') s.send('WaitTime: 30\r\n') s.send('CallerId: 1234\r\n') s.send('Application: playback\r\n') s.send('Data: /tmp/' + callnum + '\r\n') s.send('Context: from-internal\r\n') s.send('Async: true\r\n') s.send('Priority: 1\r\n\r\n') sleep(3) s.send('Action: Logoff\r\n\r\n') s.close()
And that should be it. To test just send an e-mail to emailspeak@yourserver.com with the telephone number you want to call as the subject line, and the text you want to be read in the body.
Don’t forget to write the telephone number in the format that your SIP provider is expecting it.