Blogging without knowing...

blogs

Today I needed to setup a blog without telling its users that it's a blog ;-)

Let me explain: a group of people need to share internal news using a kind of journal but we don't want them to even have to think about blogging, it's just "I'm sending news to the group" or "what happened since last time I looked".

We could use a mailing list, but for non-geeks it might be nicer to use Movable Type (that's what I'm used to) to archive, sort, search and otherwise organize the info. So the preferred scenario becomes: a) send mail to the journal, b) read the journal on a web page.

Problem is, blogging via email doesn't work out of the box with Movable Type.

After looking around I found some examples of procmail to Movable Type gateways, but none was 100% ok for me. Here's what I came up with after some fiddling, first the procmail recipe:

:0 *^TOsomewhere@yourhost.there { :0 fw | /home/bdelacretaz/blog/stripmime.pl \ | /home/bdelacretaz/blogrouter/decode-headers.pl \ | /home/bdelacretaz/blog/do-post.pl }

And here's the Perl script that posts messages to the blog:

#!/usr/bin/perl -w

post to Movable Type weblog, from email via procmail

use strict; use Net::Blogger; use Mail::Internet;

blogger setup

my $mt = Net::Blogger->new(engine => 'movabletype'); $mt->Proxy('http://your.host.there/mt/mt-xmlrpc.cgi'); $mt->Username("email"); $mt->Password("***"); $mt->BlogId(1);

read incoming mail

my $fh = \*STDIN; my $msg = Mail::Internet->new($fh, 'Modify' => 0, 'MailFrom' => 'KEEP'); my @headers = @{$msg->head()->header()}; my @body = @{$msg->body()}; my $from = $msg->get('From'); chomp($from) if ($from); my $subject = $msg->get('Subject'); chomp($subject) if ($subject); my $cc = $msg->get('Cc'); chomp($cc) if ($cc);

my $text = "De: " . $from . "\n";

if ($cc) { $text = $text . "Cc: " . $cc . "\n"; }

my $line = ""; foreach $line (@body) { $text = $text . $line; }

post to blog

my $id = $mt->metaWeblog()->newPost( title => $subject, description => $text, publish => 1 ) or die $mt->LastError();

$mt->mt()->setPostCategories( postid => $id, categories => [{categoryId => 1}] ) or die $mt->LastError();

exit;

Cool! Like Monsieur Jourdain, these people are now blogging without knowing ;-)


Update: the above didn't handle quoted-printable, I added the script shown below (found here with a minor correction), called after stripmime

#!/usr/bin/perl

Script to translate quoted-printables in MIME-encoded mail messages

Fully decodes header fields according to RFC2047

Merges multi-line header fields into single lines

use MIME::QuotedPrint ();

undef $/; # We want to treat everything read from STDIN as one line $input = ; ($headers, $body) = split (/\n\n/, $input, 2);

Process the headers:

$headers =~ s/\?=\s\n/\?=\n/g; # Lines ending with an encoded-word

have an extra space at the end. Remove it.

$headers =~ s/\n[ |\t]//g; # Merge multi-line headers into a single line. $transheaders = '';

foreach $line (split(/\n/, $headers)) { while ($line =~ m/=\?[^?]+\?(.)\?([^?]*)\?=/) { $encoding = $1; $txt = $2; $str_before = $`; $str_after = $';

Base64

if ($encoding =~ /b/i) { require MIME::Base64; MIME::Base64->import(decode_base64); $txt = decode_base64($txt); }

QP

elsif ($encoding =~ /q/i) { require MIME::QuotedPrint; MIME::QuotedPrint->import(decode_qp); $txt = decode_qp($txt); }

$line = $str_before . $txt . $str_after; }

The decode above does not do underline-to-space translation:

$line =~ tr/_/ /; $transheaders .= $line . "\n"; }

Process the body:

$transbody = MIME::QuotedPrint::decode($body);

Output the combined results. We got a free \n from

the transheaders concatenation.

print $transheaders . "\n" . $transbody;