Injecting incoming email

From Dreamwidth Notes
Jump to: navigation, search

This page describes how to make a Dreamwidth install think it is receiving incoming email without actually sending it email. This might be useful if you are testing features such as post-by-email in an environment that is not able to receive email - such as a Dreamhack.

First, prepare the email. The easiest way is to send an email to yourself from one account to another and save the resulting message, including all headers, and then edit what you need to edit. In some clients this will be via a "view source" or "view original" link, or similar. Note that sending mail from one gmail account to another does not provide all the headers that you need - the email needs to actually go out to the internet and back. In particular, anything without Return-path: will be dropped as spam. For more complex emails, such as emails with image attachments, it might be easier to build them from parts using something such as MIME::Lite, then adding/modifying the necessary headers using your favorite text editor.

Make sure that your email does not have any blank lines anywhere until the body. This includes blank lines before the start of the headers. If you did accidentally leave a blank line at the top and not notice, you might spend two and a half hours wondering why nothing worked. Ahem.

Anyway, save your email somewhere accessible from the Dreamwidth installation. I'll assume from here that it's in your home directory and that it's called email.txt.

Incoming email is processed by the incoming-email worker. Start this with

$LJHOME/bin/worker/incoming-email

on a spare terminal. This will run until stopped by Ctrl-C, without showing any output on the screen.

Then, using another terminal, you can inject your test message by

$LJHOME/bin/incoming-mail-inject.pl < ~/email.txt

Hopefully, everything worked! If you are debugging something in the email-handling code, remember that you will need to restart the incoming-email worker after you change things to make sure that it is running the latest code.

Things to check if your emails are not doing anything useful:

  • Make sure that posting by email is enabled at http://www.yourname.hack.dreamwidth.net/manage/settings/?cat=mobile, with a permitted sender and a PIN. Make sure that your From: header is the permitted sender, and that the PIN is featured in one of the allowed places. Unless you are testing what happens when it isn't ;-)
  • Make sure that your successive test emails do not have the same date. There's some code intended to do rate-limiting that will drop successive emails that have less than five minutes between their Date: headers. This may not matter if you are restarting the worker each time - I haven't checked.
  • If you want to make a post or comment by email, be aware that in the default configuration, free users are unable to do this. You will need to either use http://www.yourname.hack.dreamwidth.net/admin/pay/ to give yourself a different account type, or edit the %CAP hash in the $LJHOME/etc/config.pl file to set the emailpost capability to 1 for free users.
  • If you're wanting to inject email intended for the support board, you'll need to make sure that the address you use in the "To" (or "Cc") header is defined as the reply address for one of the support categories. You can do this by going to http://www.yourname.hack.dreamwidth.net/admin/supportcat/ (giving yourself the supportadmin:support priv if necessary), editing the category, and entering a valid email address into the "Reply address" field.
  • For some maybe-useful diagnostics, try logging into your hack's System account and looking at http://www.yourname.hack.dreamwidth.net/admin/theschwartz

The following script may be useful in building an email file with attachments. Don't forget after using it to edit the file to make sure all headers, including Return-path:, are present and correct.

#!/usr/bin/perl

# Typical use: message_with_attachment attachment_file > MIME_message_file

use strict;
use warnings;
use MIME::Lite;
use File::Type;

die "Wrong number of arguments.\n" if @ARGV != 1;
die "'$ARGV[0]' can't be empty or only spaces.\n" if $ARGV[0] =~ /^\s*$/;
die "'$ARGV[0]' must be in the current directory.\n" if $ARGV[0] =~ /\//;

my $ft = File::Type->new;
my $type = $ft->checktype_filename( $ARGV[0] );
die "Can't determine type of $ARGV[0].\n" unless defined $type;
$type = 'image/png' if $type eq 'image/x-png';

my $msg = MIME::Lite->new( From => '[email protected]', To => '[email protected]', Subject => 'A subject line', Type => 'multipart/mixed' );
$msg->attach( Type => 'TEXT', Data => 'A text body line' );
$msg->attach( Type => $type, Path => $ARGV[0], Filename => $ARGV[0], Disposition => 'attachment' );
$msg->print( \*STDOUT );