Filtering email to add as a note to an action

I’ve created a perl-script that can be added as an email filter to Sendmail so that you will be able to add an action to Tracks from that email. I had to change the API of Tracks in order to add the content of the email as a note to the new action. (update: the patch got merged!). This led to a nice discussion (also here) on the Tracks forums.

I still had two problems with my solution: 1) all email goes into one context and you have to process that to put a new action into the right context/project. And 2) mime email do not work (e.g. html mail or other mulitpart emails).

1) will be solved in the next version of Tracks. To solve 2) I’ve changed my perl script to look for mulit-part email and select the right part to use for notes. This post will show those changes.

The problem with html email is that the html also contains the html, head and body tags. These mess up your layout. Using the Detoxifier module I was able to remove those tags.

First you need two additional modules for handling MIME messages and to filter out unwanted HTML:

use Email::MIME;
use HTML::Detoxifier qw<detoxify>;

Then parse the email as a MIME mesage:

my $parsed = Email::MIME->new($mail->simple()->as_string());
my @parts = $parsed->parts;

Now scan the MIME-message-parts for the content type you want to use. This may not be the best use of Perl, but it works:

my $i=0;
my $html=-1;
my $rfc=-1;
my $plain=-1;

while ($i <= $#parts) {
if ( $parts[$i]->content_type=~/^text\/html/ ){
$html=$i;
} elsif ($parts[$i]->content_type=~/^text\/plain/ ) {
$plain=$i;
} elsif ($parts[$i]->content_type=~/^message\/rfc822/ ) {
$rfc=$i;
}
$i++;
}

my $use=$html;
if ($use <0) { $use=$rfc; }
if ($use <0) { $use=$plain; }
if ($use <0) { $use=0;}

Now put the html through the filter (non-html will pass through without problems):

my $notes = detoxify ($parts[$use]->body(), disallow => [qw(document dynamic)]);

After that you can pass the result to the notes API.

The resulting script:


#!/usr/bin/perl -w

use strict;
use Frontier::Client;
use Email::Filter;
use Email::MIME;
use HTML::Detoxifier qw<detoxify>;

# read email from stdin
my $mail = Email::Filter->new();

# Define the host first.
my $HOST = 'localhost';

my $PORT = '3000';
# Now we create the client object that will be used throughout the session.

my $client = new Frontier::Client(url => "http://$HOST:$PORT/backend/api");

# Replace with your username/password
my $username = "XXXX";

# you can get the value for your password by doing a query against the db
# select login,word from users where login like "username";
my $token = "XXXX";

# To get the context_id:
# select id,name from contexts where name like "context_name";

my $context_id = "99";
my $description = $mail->subject();
my $parsed = Email::MIME->new($mail->simple()->as_string());
my @parts = $parsed->parts;

my $i=0;
my $html=-1;
my $rfc=-1;
my $plain=-1;

# scan all parts of the mime message. Find html, plain or rfc822 entries
while ($i <= $#parts) {

if ( $parts[$i]->content_type=~/^text\/html/ ){
$html=$i;
} elsif ($parts[$i]->content_type=~/^text\/plain/ ) {
$plain=$i;
} elsif ($parts[$i]->content_type=~/^message\/rfc822/ ) {
$rfc=$i;
}
$i++;
}

#determine which part to use. Policy: first html, then rft, then plain
my $use=$html;
if ($use <0) { $use=$rfc; }
if ($use <0) { $use=$plain; }
if ($use <0) { $use=0;}

# strip document structure and dynamic content from the html
my $notes = detoxify ($parts[$use]->body(), disallow => [qw(document dynamic)]);

# now make the request to tracks and add your task
my $request = $client->call('NewTodo', $username, $token, $context_id, $description, $notes);

Explore posts in the same categories: GTD, Life, Server, Tools

Comment:

Powered by WP Hashcash