Mail Mangler

By Casey Halverson (spaceneedle at gmail.com) http://twitter.com/mailmangler/

Overview

My webmail does not offer any automated parsing or processing abilities, other than conditional forwards. So, i decided to write (and host) Mail Mangler.

Mail Mangler is a simple passthrough system which takes in emails sent to a special address, performs parsing depending on instructions, and forwards the email in its altered form to a specified destination.

Mail Mangler uses MPL, or Mangler Parsing Language. It is designed to be sent directly as the destination email address to the Mail Mangler Mail Server. This allows users to modify parsing scripts without having to interact with annoying rule processing and parsing interfaces.

Most scripts will probably fit within the 80 character limitation for email addresses. However, MPL has an extensible macro language which can be used to invoke stored parser scripts and calls to other libraries.

Mangler Parsing Language

The parsing script starts with an authentication value, contains parsing instructions in the middle, and ends with a destination value which is mapped to a specific email address.

Authentication ensures that we are not running stray spam messages as arbitrary MPL or acting as an open relay. Destination values are used to both limit the amount of characters needed for a script, as well as a deterent for wanting to "hack" or "scan" authentication codes. This limits any "attackers" to a potentially useless and obscured list of destination email addresses.

That being said, MPL is far from secure, as someone could potentially discover an MPL script in a forwarding rule (or being relayed off an SMTP server they have access to). MPL scripts should be limited to things of little importantance (ie: twitter bots, etc)

Here is an example email address:

A0000|FTranscript|W2|SPlay#message|Z00|@nwrs.net

Each MPL statement is delimited with a pipe symbol. The first character in the statement specifies the type of action or function, and the remaining are arguments.

The parser is linear, and all mail mangler actions are destructive. In other words, finding text with the "B" command will change the start position to this text, deleting all previous parts of the message. "S" will "hide" everything after the search result's first position.

MPL works this way to make it easy to isolate specific pieces of text within an email.

However, sometimes it is nice to concatenate multiple pieces of text within an email or perhaps start fresh from the beginning of the email again. MPL permits the user to "commit" a parse to memory, and either continue onward with the previously hidden message text, or even reload a fresh copy into the parsing buffer again.

This example script allows the user to send speech-to-text tweets using their voice and a telephone:

A0000|BTranscript|W2|SPlay#message|Z00|@nwrs.net

What we will do is configure google voice or gmail to forward new voicemail transcription notifications to Mail Mangler. MPL will parse out the important text and send it off to a twitter email gateway.

Here's an example of part of the body Google Voice will send us:

Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes
Content-Transfer-Encoding: 7bit

You've got new voicemail from  (206) 555-1212
Time: 11:58 AM (Aug 17, 2009)
Transcript: Jerry, it's a beautiful day.
Play message:  

Lets break down the parsing instructions to make it tweet the transcript with "A0000|BTranscript|W2|SPlay#message|Z00|@nwrs.net":

A0000 is the user authentication credentials.
BTranscript tells the parser to set the start position of the message to "Transcript", and to include the text we were searching for.
W2 tells the parser to advance to the second word (deleting "Transcript"). We could also use F instead of B to avoid this step.
SPlay#message tells the parser that the text we want stops before "Play Message" (the hash or # mark indicates a space)
Z00 tells the parser to forward the email to the pre-programmed destination "00"

Result: "Jerry, it's a beautiful day." send to a twitter email address stored as "00"

Command Reference

FunctionDescriptionArgumentsExample
AAuthentication statementAuthentication keyA0000
BFind a string, set that to the start of the message, include the search termstringBTranscript
CNumber of characters to delete from start of messagenumberC12
FFind a string, set the start of the message to after the search termstringFTranscript
JCommits the current message to memory, loads another copy of the original message, lets you edit from the beginning again. Message will be concatenated with what is stored in memory and what is currently being editednoneJ
MStored parsing macroid of macro/arg1/arg2/..M4923/45/G
PAppend printed textstringPHello#world
QQuit without sending if string is foundstringQNo#transcript#available
RReplace text with other textoptional string, optional stringRcrap\stuff
R\Same as above, deletes all textnoneR\
SStop the parser before a string, hiding the remainder of messagestringSPlay#message
WDelete text before word number specifiednumberW2
XCommit change after S, reveal hidden part of messageX
Zspecify destination email address reference numbernumberZ45
.Evaluate a number to decide an action (see note 1)operator/value/actionGT/300/Q

Note 1. Evaluate requires the user to isolate a numerical or string value and perform one of the following operators: GE, LE, GT, LT, EQ, NZ, NT, PS, NG (greater than equal to, less than equal to, greater than, less than, equal, not zero, not, positive, negative). Actions consist of Q or C (quit or continue). Naturally, strings will only be able to use the EQ and NT operators, and this function can overlap slightly with Q.

Remapped Characters:

CharacterWhat you should use
(space)#
:!
&@

Google Voice Examples

These examples parse out the following text:

Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes
Content-Transfer-Encoding: 7bit

You've got new voicemail from  (206) 555-1212
Time: 11:58 AM (Aug 17, 2009)
Transcript: Jerry, it's a beautiful day.
Play message:

Parse out time and then transcript

A0000|FTime|C3|S#(|X|FTranscript|C3|SPlay#message|Z00

This script looks for "Time", removes the colon and space, inserts the time up to the space and the parans. It then stores the current buffer into memory. We continue on the text and parse the transcript between Transcript and Play message. When we use Z to send, it automatically concatenates what we have in memory.

Result: 11:58AM Jerry, it's a beautiful day.

Create a nice short message detailing the transcript to a cell phone

A0000|R\|PCaller#|X|Ffrom##|STime|X|BTranscript|SPlay#message|Z00

This script will clear the buffer, print "Caller", store to memory and unhide the buffer, parse out the telephone number between "from " and "Time", store to memory and unhide the buffer, parse out the transcript text, and send it to the defined destination.

Result: "Caller (206) 555-1212 Jerry, it's a beautiful day."

Your Bill Is Here Examples

We all hate bills, and here are some examples ways of dealing with them. This is just a small clip from an email notification i get about my power bill.

You have a new e-Bill from PSE - Puget Sound Energy  Biller=
Account Number: ******1111  Due Date: 01/01/2034    Amount Due: 395.10 =
Account Balance:   How do I pay this e-Bill?  Note: If you have=
already paid this bill, please disregard this message. It is simply a remi=
nder that you have an e-Bill.   To pay this e-Bill, follow these steps:  1.=

Get a text notification of your power bill amount

A0000|\R|PPSE#Bill#|X|FAmount#Due|W3|S#|Z01|

First we will clear the buffer, print out "PSE Bill ", store into memory and unhide the rest of the buffer, parse out the dollar amount between "Amount Due" and the space. Send it to the email address for your cell phone (01).

Tweet to your roommate publically when your power bill is over $300

A0000|Ft#Due|W3|S#|.\LT\300\Q|R\|P&geek#PSE#is#$|J|FAmount#Due|W3|S#|Z02|

First, we parse out the amount due in the above email. We perform the evaluate function to determine if it is less than 300. If so, the MPL is told to quit. If not, we clear the buffer without committing it, write "@geek PSE is $395.10", and send it to our email to twitter gateway.