Get Firefox! Viewable with any browser! Valid HTML 4.01! Valid CSS! OpenOffice.org
Text size: 

Mozilla/Firefox and external mailers

mailto is not a registered protocol Until recently, it was impossible to have the Unix version of Mozilla invoke an external MUA (Mail User Agent) when the user clicked on a "mailto:" link. The options were to use Mozilla's integrated MUA, Messenger, or to have a dialog box pop up saying that "mailto is not a registered protocol". These days of frustration are now over!

The systems on which I did this are all based on Slackware Linux 9.0 running an in-house compiled Mozilla-1.6a. Credit goes both to Boris Zbarsky and to Jerry Talkington on the netscape.public.mozilla.unix newsgroup for pointing me in the right direction and giving me workable solutions to the problem at hand.

Please let me remind you that this document only deals with UNIX versions of Mozilla and Firebird. If you are a Windows user or a MacOS user then this page is not for you.

Recent versions of Mozilla - indeed, this feature was only introduced as of the September 17th 2003 nightly build - now have settings whereby you can tell Mozilla that mail is to be handled by an external application and which external application does the work. If, on the other hand, you don't want to upgrade your version of Mozilla to something so "bleeding edge", you can always fall back on Mozex (see mozex.mozdev.org) which works as from Mozilla-1.3 and Firebird-0.6, and you need not concern yourself with anything more on this page.

Before going any further, you're going to need a wrapper in the form of a binary executable or a script, which invokes your mailer. Mozilla is going to invoke this wrapper and pass it the entire mailto: URL as a command line parameter, including any '%' escape sequences, exactly as it was included in the anchor tag on the web page. For example, if you were to click on my e-mail address at the bottom of this page, and assuming you told Mozilla to run a script called "mailto.sh", which resides in a directory listed in your $PATH environment variable (how to do this will be explained later), Mozilla is going to shell out this command:

It is now up to your script to separate the various parts of the mailto: link, such as the recipient's e-mail address, any Cc or Bcc addresses, the subject etc., and feed them to the MUA. Personally, I use sylpheed, which is extremely practical because you can feed the entire link to it and it sorts out the various parts. Therefore, my mailto.sh script looks like this:

#!/bin/bash

sylpheed --compose "$1"

It couldn't be simpler.

By clicking on the aforementioned link, Mozilla will invoke my wrapper script with the appropriate command line parameter, and my script will pass this parameter along verbatim to sylpheed:

Note that the quotes around the $1 in my script are crucial from a security point of view. Imagine the consequences of you clicking on a link like this:

mailto:someone@somedomain.tld; rm -Rf $HOME/*

Without the quotes, my script would end up doing this:

sylpheed --compose mailto:someone@somedomain.tld; rm -Rf $HOME/*

...which could have unpleasant consequences...

Other MUAs aren't as helpful as sylpheed in that you have to break the URL down into its various parts and spoon-feed them to the MUA in your wrapper script. The following Perl script, feedmua.pl, will do this for you and split the link into the variables called $RECIPIENT, $CC, $BCC, $SUBJECT and $BODY. You can download this script here.

#!/usr/bin/perl -w

# feedmua.pl - (c) 2003 Godwin STEWART, all rights reserved.
# Version 0.1 / 22-OCT-2003
# Released under the GNU General Public License Version 2, the terms of which
# are available here: http://www.fsf.org/licenses/gpl.html
#
# This software is provided as is, with no guarantee of merchantability or
# fitness for any purpose. Use it at your own risk.

# bail out with an error condition if nothing was passed to the script
exit(1) if ( scalar(@ARGV) < 1 );

# declare a few local variables
my ($LINK, $RECIPIENT, $CC, $BCC, $SUBJECT, $BODY) = ("", "", "", "", "", "");
my (@PARTS, $SEGMENT, $CMDLINE);

# grab the link passed to us
$LINK = $ARGV[0];

# bail out with an error condition if it doesn't begin with "mailto:"
exit(1) unless ( $LINK =~ m/^mailto\:/i );

# strip the mailto at the beginning
$LINK =~ s/^mailto\:(.*)/$1/i;

# bail out with an error condition if nothing's left
exit(1) if ( length($LINK) == 0 );

# What we have now is something of the form
#
#  address?variable1&variable2&variable3&...
#
# Replace the '?' with a '&' and then split the string on '&' boundaries.
$LINK =~ s/\?/&/g;
@PARTS = split("&",$LINK);

# Treat @PARTS as a stack and pop elements off it as and when.
#
# The first element should be the recipient.
$RECIPIENT = shift(@PARTS);

# bail out with an "ok" condition if this was all there was in the link
exit(0) if ( scalar(@PARTS) == 0 );

# now loop through the remaining elements parsing them until there are
# none left

while ( scalar(@PARTS) ) {

  $SEGMENT = shift(@PARTS);

  if ( $SEGMENT =~ m/^cc=/i ) {
    ( $CC = $SEGMENT ) =~ s/^cc=(.*)/$1/i;
    next;
  }
  
  if ( $SEGMENT =~ m/^bcc=/i ) {
    ( $BCC = $SEGMENT ) =~ s/^bcc=(.*)/$1/i;
    next;
  }
  
  if ( $SEGMENT =~ m/^subject=/i ) {
    ( $SUBJECT = $SEGMENT ) =~ s/^subject=(.*)/$1/i;
    next;
  }
  
  if ( $SEGMENT =~ m/^body=/i ) {
    ( $BODY = $SEGMENT ) =~ s/^body=(.*)/$1/i;
    next;
  }

}

# From here onwards, the variables $RECIPIENT, $CC, $BCC, $SUBJECT
# and $BODY contain what you'd expect them to contain. If the
# corresponding item wasn't set in the mailto: link then the
# variable contains an empty string.
#
# Now, all you have to do is build a command line which feeds these
# variables to your mailer.
#
# For example, kmail expects a command line like this:
#
# kmail --composer -c <Cc_recipients> -b <Bcc_recipients> -s <subject> --body <body> <recipient>
#
# Always enclose the values in quotes so that empty values are in fact counted as
# empty arguments rather than just skipped altogether. So your command would look
# something like this:
#
# $CMDLINE = "kmail --composer -c \"$CC\" -b \"$BCC\" -s \"$SUBJECT\" --body \"$BODY\" \"$RECIPIENT\"";
#
# See http://mozex.mozdev.org/arguments.html for details of the command line arguments
# of other mailers.

# No further processing is required in this script so hand the control over
# to the mailer rather than forking and waiting.

exec $CMDLINE;

So, if you're a sylpheed user like me, you can get away with the 3-line shell script, mailto.sh, or if you use another mailer you'll have to use the longer Perl script, feedmua.pl. In order to do this, you're going to have to dig down deep into the settings contained in your prefs.js file, although Mozilla itself does provide a useful interface for this. Open a new window or tab and enter "about:config" in the address bar. You'll end up with something like this:

Mozilla's about:config screen

The settings we need to adjust are network.protocol-handler.external.mailto and network.protocol-handler.app.mailto, but first of all, let's whittle the literally hundreds of settings presented to us here down to something more manageable. Enter "protocol-handler" into the filter bar. You should get far fewer settings to sort through:

Mozilla's about:config screen, filtered

What we need to do now is create the following preference settings:

network.protocol-handler.external.mailto = true

and then:

network.protocol-handler.app.mailto = mailto.sh
or
network.protocol-handler.app.mailto = feedmua.pl
depending on which mailer you use.

In order to create a setting, right-click on any one of them, select "New" and then "Boolean" in the context menu which appears. When prompted for the name of the preference, enter network.protocol-handler.external.mailto :

Name of the first preference setting

Next you'll be asked for the value to be given to that setting. In this case, we want it to be true:

Value of the first preference setting

Next, we have to create the other preference setting which tells Mozilla what to run when we click on a mailto: link. In my case it's the mailto.sh script. So, right-click and select "New" then "String" this time:

Name of the second preference setting Value of the second preference setting

The about:config screen isn't updated immediately when a new value is created, so fiddle with the filter bar to force an update. The about:config screen should now reflect the new preference settings you just made:

Mozilla's about:config screen, with the new prefs

From now on, a click on a mailto: link in Mozilla should fire up a composing window in your mailer, with all the details already filled in, instead of brushing you off with an unfriendly "mailto is not a registered protocol" message.

NAVIGATION:
>> /

Last update: 24-OCT-2006
This page has been served 5402 times since 22-OCT-2003