Using mail(1)
Intro
Oh, no!
You have a fresh install
and the only way to read
your welcome message from Theo
requires using
mail
.
Or perhaps you've exited some long-running program
and your shell informs you
However, upon launching
mail
,
most users find that the interface has all the friendliness of
ed(1)
.
For decades,
Unix-like systems have offered
mail(1)
as a way to read the system mailbox
and send mail.
While not as flashy or featureful as more modern
MUAs
like
s-nail,
Mutt,
NeoMutt,
Alpine,
or
Aerc
(or even graphical MUAs like
Claws Mail,
Thunderbird,
KMail,
or Gnome
Evolution),
it provides a surprising bit of functionality
hidden under the hood.
History
Over the years,
a variety of
CLI
programs have called themselves some form of "mail",
including
mail
,
Mail
,
mailx
,
heirloom-mail
,
and
s-nail
,
with subtle differences in each of them.
For purposes of this post,
I'll try to stick mostly to
mail
/mailx
,
as defined by POSIX
which means
- no IMAP/POP/SMTP support
-
no Maildir or MH support,
only classic
mbox
format - no built-in spam filtering
- no threading
-
no native support for
MIME
types other than
text/plain
(so notext/html
)
mailx
.
Specifically, all examples here
should work in
mail
as provided by
FreeBSD
&
OpenBSD
base systems.
This post assumes some basic system configuration and will discuss the three essential modes of operation:
- send mode
- interactive mail reading mode, and
- mail composition mode
System configuration expectations
By default,
most Linux & BSD systems provide
local mail receipt & delivery
out of the box on a fresh install,
whether with
sendmail,
exim
,
Postfix,
or my favorite,
OpenSMTPD.
To exchange mail with external systems,
you'll have to configure your
MTA
as well as possibly modify your
DNS
to point your
MX
record at your server,
set up
SPF
&
DMARC
and you might want some sort of spam-filtering solution in place.
However, since MTA choice & configuration
fall outside the scope of this post,
use whatever you prefer
as long as your
MDA
delivers to the user's system
mbox
(usually
/var/mail/$USER
or
/var/spool/mail/$USER
)
and your MTA has compatibility with
sendmail
(usually done through a binary or link at
/usr/sbin/sendmail
).
Finally,
mail
assumes that it can lock mailboxes
at the file-system level.
On local file-systems,
this doesn't generally pose a problem.
However, if your system
mbox
resides on an
NFS
share with unreliable locking,
you may encounter issues/conflicts
if more than one process attempts to modify the mailbox.
Essential modes of operation
Send mode
The most simple of the modes,
this expects the email message body on
stdin,
an optional subject passed with the
-s
option,
CC
&
BCC
fields with the
-c
&
-b
options,
followed by the list of recipient(s).
Send mode works well in scripts
to email output of commands,
and often
cron
&
at
use
mail
to send the results of each task to the owner.
If
mail
reads from an interactive terminal,
it affords
tilde-escape
operations for editing the message.
When finished with the message,
use an
EOF
with
ctrl+d
to send the message.
Mail reading mode
Starting mail
If you currently have mail in your system mailbox,
POSIX shells should inform you (roughly) every
$MAILCHECK
seconds
(default=600, or 10 minutes)
if the last-modified time
of the system mailbox
(as specified by
$MAIL
)
has changed.
Launching
mail
with no arguments opens
mail
,
displays
a screenful of message headers,
and leaves you at an
"&"
prompt.
Exiting mail
To quit back to your shell without modifying the mailbox, use the x/exit command.
If you use the
q/quit
command or type
ctrl+d
to send an
EOF,
it will change the message status of unread messages from
N
(new)
to
U
(unread).
By default,
if you have read any of the messages in your system mailbox,
they will get moved to
~/mbox
upon quitting with
q.
The
hold
setting prevents
mail
from moving messages out of the system mailbox
unless you explicitly (re)move them.
Listing messages
By default,
when
mail
starts up,
it shows you a screenful of message-summaries,
one per line.
Each message has an identifying number/index
that should remain valid for the entire session.
The header-listing consists of the following fields:
-
flags
(New,
Unread,
Preserved,
M send to
mbox
, and * saved) - message index
- sender
- date
- size (in lines and bytes)
- subject
If you have more than one screenful of messages,
you can use the
z
command to list the next screenful,
z-
to list the previous screenful,
and
h
to re-display the current screenful.
When you first start
mail
,
it displays the first page of message-summaries
as if you had typed
h.
To list message summaries matching particular criteria, you can use the f/from command with a message-list filter. Message-list filters can consist of a single message number,
multiple message numbers,
or a range of numbers:
You can use a $ to indicate the last message in the mailbox:
These can combine to list particular messages by number & range:
If you want to refer to all messages in the mailbox, you can use *
though this may scroll past if you have more than one screenful of messages.
Additionally, you can list messages by category of message
- :d
- deleted messages
- :n
- new messages
- :o
- old messages
- :r
- read messages
- :u
- unread messages
Finally, you can list messages by searching.
If you use a regular string,
mail
will search the "From" header for mail from that recipient:
You can use partial matching as well:
If you prefix the search string with a /, it will search messages' Subject field:
Displaying messages
To display a message,
use the
p/print
command.
Without a message-list following the
p/print
command,
mail
will print the message headers and the body
of the current message.
If the length of the message exceeds the height of the screen
(or the value of the
crt
setting, if set),
the headers and body will get sent to your
$PAGER
.
A lot of headers clutter that output,
so I often use
retain
(or
ignore
)
to winnow these to what I care about.
I
retain
only those headers I want to see:
Much better. Well, except for the quality of the thesis.
After using
retain
,
if you subsequently want to see
all
the headers,
you can use the
P/Print
(with a capital "P")
command.
Deleting (and undeleting) messages
The
d/delete
command deletes the current message,
while
u/undelete
undeletes a deleted message.
Both accept a list of message-IDs
like the
print
command.
You can undelete messages
as long as you haven't closed
the current mailbox file.
If you accidentally delete a bunch of messages
remember you can always use
x
to quit safely without writing any changes,
Replying to messages
After reading a message,
you can use the
r/reply
command to reply to all the recipients,
or the
R/Reply
command to reply only to the author of the message.
By default,
mail
doesn't include the original message,
so you may want to use the
~m
command to read the current message
into the reply,
prefixed with
indentprefix
.
The section on mail composition has more details on how to edit your reply.
Composing new messages
To compose a new message from within
mail
,
use the
m/mail
command,
specifying the recipient.
The section on mail composition has more details on how to compose your message.
Filing messages
Once you have read a message, rather than delete it, you may prefer to file it in a separate mbox archive so it doesn't clutter your main inbox. Use the s/save command to specify an mbox file. You can specify a message-list between the save command and the mbox filename to save multiple messages in one command.
Alternatively, if you would like to save a copy of the message, while keeping the original in the current mailbox, use the c/copy command which has the same syntax as save.
Changing mailboxes
Great.
Now you can read mail
from your system mailbox.
And you can file mail in other mbox stores.
How do you access those folders?
You can either specify it on the shell command-line with
-f
or within mail using the
file
command.
The
folder
setting
allows you to prefix a folder-name with "+"
to refer to mbox stores in that folder
regardless of your current working-directory.
Additionally, you can use
"%" to refer to your system mailbox,
"#" to refer to the previous folder you had open,
and "&" to refer to your
MBOX
folder.
set folder="mail" copy 8 +thesis folders bills thesis
Mail composition mode
When creating a new message, either via the shell
mail -s "My subj" user@example.comor
mail
command-line
m user@example.com Subject: My subjectby default
mail
lets you enter your message
one line at time
and terminate it with a period or EOF:
m bob@example.edu Subject: thesis feedback Thanks for your helpful feedback. .
Tilde escapes
While convenient to type your message
and send it,
sometimes you want to edit the message
in your
$EDITOR
,
revise the list of recipients,
change the Subject line,
or include a message's contents
for a point-by-point reply.
By entering a message-body line
beginning with a tilde
followed by a command-letter,
mail
lets you make such modifications.
And if you want to abandon the message,
use the
~q
command to save the draft in
~/dead.letter
,
or use the
~x
to abandon the message completely.
If you saved a draft,
you can read it back in with
~d.
Using ~? will give you the full list of allowed tilde commands.
Use ~t recipient, ~c recipient, and ~b recipient to add recipients to the "To:", "CC:", and "BCC:" recipient-lists respectively. The ~s lets you edit your "Subject:" header. Or use ~h to edit each header in turn.
Most usefully,
the
~e
and
~v
commands let you edit the current message
in your
$EDITOR
and your
$VISUAL
editors respectively.
When you return from your editor,
you can continue to append to the message where you left off.
To display the message as it currently stands,
use the
~p
tilde command.
As with other mailers,
sometimes you want to include the content of other messages.
The
~f message-list
&
~m message-list
commands let you read one or more messages
from your current mailbox
into the current message.
If you omit the
message-list,
mail
uses the current message.
If you have set the
indentprefix
option
(I recommend the internet standard "> "),
the
~m
will prefix each line with the corresponding value:
set indentprefix="> " m bob@example.edu Subject: thesis feedback ~m /thesis Thanks for your helpful feedback. .as commonly used for replies. By default, only the retained headers get included. If you want all the headers, use the uppercase versions ~F & ~M instead.
Alternatively, you might want to read output from an external file (with ~r filename) or command (with ~! command)
Finally, sometimes you want
to pass your message
through an external utility
like
rot13(6)
,
b1ff(6)
,
or a spell-check utility.
The
~| command
command lets you filter the message.
Beware: if editing over ssh
Both
mail
&
ssh
use tilde-escapes at the beginning of the line.
To send a tilde over
ssh
you may have to hit
~
twice to send the tilde to
mail
.
Address book
Not having the best memory,
I prefer to let my computer keep track of contacts.
I want to type "john" as the recipient
and let my mail program figure out who I mean.
Do I want to forget any family members
when sending out important family-wide updates?
No way!
The "alias" file contains tuples beginning with the keyword
alias
followed by the nickname you want to use,
and one or more addresses to expand into.
This lets me compose a message to "john" or "family"
and have
mail
expand to the correct addresses.
Settings
Your
~/.mailrc
file can contain startup commands & settings
to tweak the behavior of
mail
so this section covers the ones I find useful.
I've included my
~/.mailrc
below as an example.
As listed above,
I set my
retain
to a very small subset of headers
that I actually want to see,
usually
"Subject",
"Date",
and "CC".
crt
-
By default,
mail
determines the number of lines based on the display device and uses this to determine when to pass the output through$PAGER
for display. Settingcrt
lets you override this. For instance, on one machine, I set this 120 lines and commonly read my 3–4 system messages by issuing p * to display all the messages. Any one message falls below that threshold, letting me see an individual message without paging. But I find it handy to read all of them together in$PAGER
in one quick skim. folder
-
By default,
mail
assumes all your mail-folders reside in your$HOME
directory. If you use the folders command to list available mbox files, it may return lots of non-mbox files. Instead, if you store your mail in a subdirectory, you can set that here. Additionally, regardless of your current working-directory, you can prefix folder-names with a "+" to refer to folders in yourfolder
directory header
-
Each time you open a folder
(whether at startup
or using the
file
command),
mail
displays a screen-full of headers. If you don't want this behavior, setnoheader
. hold
-
When quitting and leaving your system mailbox,
by default
mail
will move every read-message into yourMBOX
store (~/mbox
by default). By settinghold
,mail
will leave messages in your system mail-store until you manually move or delete them. indentprefix
-
When
replying to a message,
common convention suggests
that you prefix each quoted line with the string
"> "
The
indentprefix
setting controls this. MBOX
-
This specifies your default "mbox"
local mail store,
defaulting to
~/mbox
but I prefer to set this to a file within my~/mail
hierarchy record
-
When sending a message,
often times you want to keep that message around.
The
record
setting lets you specify the folder in which to put a copy. Unfortunately, there's no folder-name for the current folder, but you can use something like+sent
to keep them all in the same folder. searchheaders
-
Normally when specifying a message-list
by searching with
/,
mail
will only search the Subject header. However, if you enablesearchheaders
, you can prefix your search term with a header-name to search. This lets you do things like f /To:dean@example.edu (to search for all messages sent to the dean) or f /Date:Jul (to search for messages sent in July). If you omit the header, it defaults to searching the Subject header as usual.
As promised,
an excerpt of my
~/.mailrc
Tips & tricks
Deleting all-but XYZ
I receive a number of messages from system-administration processes. Some come daily, some weekly, some monthly. Some have security advisories, while others give general system information. So I usually want to delete the non-security-related ones. However, the subject lines make this more challenging. The trick? Delete all of them, then undelete the security-related ones:
I can then review these more-relevant messages without the noise of the other messages.
Quickly processing messages
On some machines,
I want to read all the mail in my
$PAGER
pressing
space
to show a screen-full at a time
and then delete all the messages unless
something surprising shows up.
Other times, I want to read each message and process as I go. After displaying a message, I can hit enter (with no command) to display the next message automatically. Alternatively, the dp command will delete the current message and print the next message in one go. It may only save one keypress, but I find it useful