GNU Mailutils Manual (split by node):   Section:   Chapter:FastBack: Programs   Up: mail   FastForward: Libraries   Contents: Table of ContentsIndex: Function Index

3.5.5 Composing Multipart Messages

Multipart messages (or MIME, for short) can be used to send text in character sets other than ASCII, attach non-text files, send multiple parts in alternative formats, etc.

Technically speaking, the boolean variable mime controls this feature. If it is set (see Setting and Unsetting the Variables), MIME will create MIME messages by default. The variable can be set in the global or user configuration file (see Mail Configuration Files), using the following command:

set mime

It can also be set from the command line, using the --mime option.

GNU mail automatically turns on the MIME mode, when it is requested to send a non-plaintext message, or a message in character set other than ASCII, when the encoding is specified, or when attachments are given.

To send a message in another character set, specify it with the --content-type option:

mail --content-type 'text/plain; charset=utf-8'

The --encoding specifies the encoding to use:

mail --content-type 'text/plain; charset=utf-8' --encoding=base64

Its argument is any encoding supported by GNU mailutils. The two most often used encodings are ‘base64’ and ‘quoted-printable’.

To specify the charset from mail interactive section, enable the “edit headers” mode (set editheaders) and add the needed Content-Type header manually.

GNU mail also gives you a possibility to attach files to the message being sent.

The simplest way to attach a file from command line is by using the --attach (-A) option. Its argument specifies the file to attach. For example, the following will attach the content of the file archive.tar:

$ mail --attach=archive.tar

By default, the content type will be set to ‘application/octet-stream’, and the attachment will be encoded using the ‘base64’ encoding. To change the content type, use the --content-type option. For example, to send an HTML attachment:

$ mail --content-type=text/html --attach=in.html

The --content-type option affects all --attach options that follow it, and the message body (if any). To change the content type, simply add another --content-type option. For example, to send both the HTML file and the archive:

$ mail --content-type=text/html --attach=in.html \
       --content-type=application/x-tar --attach=archive.tar

To change the content type of the message body when sending a message with attachments, use the trailing --content-type option, i.e. the option not followed by another --attach option:

$ mail --content-type=text/html --attach=in.html \
       --content-type=application/x-tar --attach=archive.tar \
       --content-type=text/plain

This example adds two attachments with different content types and switched back to the ‘text/plain’ content type for the message body.

The encoding to use is set up by the --encoding option. As well as --content-type, this option affects all attachments supplied after it in the command line as well as the message body read from the standard input, until changed by the eventual next instance of the same option. Extending the above example:

$ mail --content-type=text/html --encoding=quoted-printable \
       --attach=in.html \
       --content-type=application/x-tar --encoding=base64 \
       --attach=archive.tar

A trailing --encoding option sets the encoding of the message body.

Each attachment can also be assigned a description and a file name. Normally, these are the same as the file name supplied with the --attach option. However, you can change either or both of them using the --content-name and --content-filename, correspondingly. Both of these options affect only the next --attach (or --attach-fd, see below) option.

By default, the message will be assigned the content type ‘multipart/mixed’. To change it to ‘multipart/alternative’, use the --alternative command line option. Using this option also sets the ‘Content-Disposition’ header of each attached message to ‘inline’.

All the examples above will enter the usual interactive shell, allowing you to compose the body of the message. If that’s not needed, the non-interactive use can be forced by redirecting /dev/null to the standard input, e.g.:

$ mail --attach=archive.tar < /dev/null

This will normally produce a message saying:

mail: Null message body; hope that's ok

To suppress this message, unset the ‘nullbodymsg’ variable, as shown in the example below:

$ mail -E 'set nonullbodymsg' --attach=archive.tar < /dev/null

The option --attach=- forces mail to read the file to be attached from the standard input stream. This option disables the interactive mode and sets ‘nonullbodymsg’ implicitly, so that the above example can be rewritten as:

$ mail --attach=- < archive.tar

Special option is provided to facilitate the use of mail in scripts. The --attach-fd=N instructs the program to read the data to be attached from the file descriptor N. The above example is equivalent to:

$ mail --attach-fd=0 < archive.tar

Attachments created with this option have neither filename nor description set, so normally the use of --content-name and/or --content-filename is advised.

The option --skip-empty-attachments instructs mail to skip creating attachments that would have zero-size body. This option affects all attachments created by --attach and --attach-fd options appearing after it in the command line. It also affects the handling of the original message body. To cancel its effect, use the --no-skip-empty-attachments option.

Here are some examples illustrating how it works.

First, consider the following command line

$ mail --attach=archive.tar </dev/null

Assume that archive.tar is not empty.

This will create a MIME message of two parts: the first part having ‘text/html’ type and empty body, and the second part of type ‘application/octet-stream’, with the content copied from the file archive.tar.

Now, if you do:

$ mail --attach=archive.tar --skip-empty-attachments </dev/null

then the created MIME message will contain only one part: that containing archive.tar.

If the file archive.tar has zero length, the resulting archive will still contain the ‘application/octet-stream’ part of zero length. However, if you place the --skip-empty-attachments option before --attach, then the produced message will be empty.

The following Perl program serves as an example of using mail from a script to construct a MIME message on the fly. It scans all mounted file systems for executable files that have setuid or setgid bits set and reports the names of those files in separate attachments. Each attachment is named after the mountpoint it describes.

The script begins with the usual prologue stating the modules that will be used:

#!/usr/bin/perl

use strict;
use autodie;

Then global variables are declared. The ‘@rcpt’ array contains the email addresses of the recipients:

my @rcpt= 'root@example.com';

The ‘@cmd’ variable holds the mail command line. It will be augmented for each file system. The initial value is set as follows:

my @cmd = ('mail',
           '-E set nonullbodymsg',
           '--content-type=text/plain');

The find utility will be used to locate the files. The script will start as many instances as there are mountpoints. Those instances will be run in parallel and their standard output streams will be connected to file descriptors passed to mail invocation in --attach-fd options.

The descriptors will be held in ‘@fds’ array. This will prevent them from being wiped out by the garbage collector. Furthermore, care should be taken to ensure that the O_CLOEXEC flag be not set for these descriptors. This sample script takes a simplistic approach: it instructs Perl not to close first 255 descriptors when executing another programs:

my @fds;
$^F = 255;

The following code obtains the list of mount points:

open(my $in, '-|', 'mount -t nonfs,noproc,nosysfs,notmpfs');
while (<$in>) {
    chomp;
    if (/^\S+ on (?<mpoint>.+) type (?<fstype>.+) /) {

For each mountpoint, the find command line is constructed and launched. The file descriptor is pushed to the ‘@fds’ array to prevent it from being collected by the garbage collector:

	open(my $fd, '-|',
	     "find $+{mpoint} -xdev -type f"
             . " \\( -perm -u+x -o -perm -g+x -o -perm -o+x \\)"
             . " \\( -perm -u+s -o -perm -g+s \\) -print");
	push @fds, $fd;

Now, the mail command is instructed to create next attachment from that file descriptor:

        my $mpname = $+{mpoint};
        $mpname =~ tr{/}{%}; 
        push @cmd,
             "--content-name=Set[ug]id files on $+{mpoint} (type $+{fstype})",
             "--content-filename=$mpname.list",
             '--attach-fd=' . fileno($fd);
    }
}
close $in;

Finally, the emails of the recipients are added to the command line, the standard input is closed to make sure mail won’t enter the interactive mode and the constructed command is executed:

push @cmd, @rcpt;
close STDIN;
system(@cmd);

GNU Mailutils Manual (split by node):   Section:   Chapter:FastBack: Programs   Up: mail   FastForward: Libraries   Contents: Table of ContentsIndex: Function Index