How I send email from the command line

0

Email is a ubiquitous messaging service and is available on devices ranging from work and home desktop computers to various mobile devices such as smart phones and tablets. There are times, however, when I find it useful to send email from the Linux command line. I’m not talking about using one of the text mode clients like Alpine. I mean sending email directly from the command line.

For example, I may want to send an email of the results from a command, or a series of commands, directly to an email address. Many times, that’s to myself, but it can be to others as well.

SendMail

Sendmail is a common mail transfer agent (MTA). It has been around since 1983 and is still widely used on many email servers, including mine. There are a number of other good MTAs available, many of which are open source.

Although I use SendMail for my domain email server, it’s also useful on a host that is not being used as the primary email server for a domain. SendMail can be used on any host to provide an MTA to deal with emails sent to root by various system level applications and servers. If not sent on to an email server, the local emails will be sent to the root user on the local host. Thus, they may never be read and acted upon. SendMail is required for each host that is intended to send its system management emails to a central mail server for further relay and distribution. When a network of hosts is configured to send all emails to the email server for the domain, that central email server is called a smart host.

Just to clarify, the spelling, “SendMail,” with uppercase “S” and “M,” is the official name, while “sendmail,” is the command in all lowercase.

Sendmail and mailx installation

Let’s start by installing SendMail on our host because it’s required for sending email from the command line, and mailx which allows us to send email from the command line. Do this as the root user on your host.

Your host may already have the sendmail package, the MTA, installed, and sendmail-cf. The sendmail-cf package provides the makefiles1 and configuration files that allow configuration and recompilation of sendmail.mc and other SendMail configuration files and databases. You won’t need any of the tools provided by sendmail-cf for this experiment, so we won’t install it. It’s fine if it’s already installed and we can ignore it.

The mailx program is an email client that can be used as a text mode email client and as a command in a pipeline to send a data stream from its STDIN to the local mail transfer agent. This is a good tool for use to send emails from scripts. We can also use it from the command line to easily send test emails from the Linux command line.

If either of these packages is already installed it won’t be reinstalled and nothing bad will happen. DNF will simply display a message and ignore the already installed packages.

# dnf -y install sendmail mailx

This installation does not require a reboot and no configuration changes are needed. Now start SendMail.

# systemctl start sendmail

You should check the status of SendMail to verify that it is running.

# systemctl status sendmail
● sendmail.service - Sendmail Mail Transport Agent
     Loaded: loaded (/usr/lib/systemd/system/sendmail.service; disabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: active (running) since Fri 2024-08-30 20:29:09 EDT; 2s ago
    Process: 1930 ExecStartPre=/etc/mail/make (code=exited, status=0/SUCCESS)
    Process: 1934 ExecStartPre=/etc/mail/make aliases (code=exited, status=0/SUCCESS)
    Process: 1943 ExecStart=/usr/sbin/sendmail -bd $SENDMAIL_OPTS $SENDMAIL_OPTARG (code=exited, status=0/SUCCESS)
   Main PID: 1945 (sendmail)
      Tasks: 6 (limit: 9471)
     Memory: 15.3M (peak: 22.9M)
        CPU: 395ms
     CGroup: /system.slice/sendmail.service
             ├─1945 "sendmail: accepting connections"
             ├─1964 "sendmail: 47V0T9Zu001964 localhost [127.0.0.1]: DATA"
             ├─1971 "sendmail: yorktown.both.org.: idle"
             ├─1972 "sendmail: ./47V0T9Zm001964 yorktown.both.org.: client DATA status"
             ├─1973 "sendmail: ./47V0T9Zo001964 yorktown.both.org.: client DATA status"
             └─1975 "sendmail: ./47V0T9Zs001964 yorktown.both.org.: client EHLO"

Sending the email

Now as a non-root user on your host, enter the following command. The -s option of the mailx command sets the subject text — in double quotes — of the email. Substitute your real email address for test@example.com in the command.

$ echo "Hello world" | mailx -s "Test email 1 from $HOSTNAME" test@example.com

Note that the mailx command adheres to the Linux Philosophy tenet that “silence is golden.” Thus, it doesn’t display any messages on the terminal if everything works properly from its standpoint. It doesn’t necessarily mean that the message was delivered.

Verify that you receive the email in your email client. If it’s not received in a minute or so, you can use the same command with the -v option to display verbose messages that can provide a clue as to what failed. This is what using the -v option looks like on my host when everything is working. Once again, substitute your real email address for test@example.com in the command.

$ echo "Hello world" | mailx -vs "Test email 1 from $HOSTNAME" test@example.com
s-nail: No such file to load: /home/dboth/.mailrc
s-nail: Warning -- v15-compat=yes will be default in v14.10.0!
s-nail: P(seudo)R(andom)N(umber)G(enerator): arc4random
test@example.com... Connecting to [127.0.0.1] via relay...
220 testvm1.both.org ESMTP Sendmail 8.18.1/8.18.1; Fri, 30 Aug 2024 21:53:06 -0400
>>> EHLO testvm1.both.org
250-testvm1.both.org Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH DIGEST-MD5 CRAM-MD5
250-STARTTLS
250-DELIVERBY
250 HELP
>>> STARTTLS
220 2.0.0 Ready to start TLS
>>> EHLO testvm1.both.org
250-testvm1.both.org Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH DIGEST-MD5 CRAM-MD5
250-DELIVERBY
250 HELP
>>> MAIL From:<dboth@testvm1.both.org> SIZE=144 AUTH=dboth@testvm1.both.org
250 2.1.0 <dboth@testvm1.both.org>... Sender ok
>>> RCPT To:<test@example.com>
>>> DATA
250 2.1.5 <test@example.com>... Recipient ok
354 End data with <CR><LF>.<CR><LF>
>>> .
250 2.0.0 47V1r6Km126007 Message accepted for delivery
test@example.com... Sent (47V1r6Km126007 Message accepted for delivery)
Closing connection to [127.0.0.1]
>>> QUIT
221 2.0.0 testvm1.both.org closing connection

The data displayed by the -v option allows viewing the complete conversation between mailx and the receiving email server. In this case testvm1 is the server and SendMail on testvm1 received the email correctly.

HOWEVER, since the destination I used is example.com, the attempt by SendMail on testvm1 to connect with an email server at example.com fails. But we have no way of knowing that unless we use mailx to look for a bounce. So set this up for yourself. Use the command echo “Hello world” | mailx -vs “Test email 1 from $HOSTNAME” test@example.com and then start mailx in its client mode.

Type mailx in your terminal session — the same one you sent the email from — and you should see a single email from “Mail Delivery Subsys.” Type 1 and press Enter to view the message.

$ mailx
s-nail version v14.9.24.  Type `?' for help
/var/spool/mail/dboth: 1 message
▸   1 Mail Delivery Subsys  2024-08-30 21:53   67/2322  "Returned mail: see transcript for details                                                        "
& 1
[-- Message  1 -- 67 lines, 2322 bytes --]:
Date: Fri, 30 Aug 2024 21:53:06 -0400
From: Mail Delivery Subsystem <MAILER-DAEMON@testvm1.both.org>
Message-Id: <202408310153.47V1r6Kl126009@testvm1.both.org>
To: <dboth@testvm1.both.org>
Subject: Returned mail: see transcript for details


[-- #1.1 11/311 text/plain, 7bit, us-ascii --]

The original message was received at Fri, 30 Aug 2024 21:53:06 -0400
from localhost [127.0.0.1]

   ----- The following addresses had permanent fatal errors -----
<test@example.com>
    (reason: 556 Host does not accept mail: MX 0 .)

   ----- Transcript of session follows -----
554 5.0.0 Service unavailable

[-- #1.2 14/415 message/delivery-status, 7bit, us-ascii --]

[-- No MIME handler installed, or not applicable --]

[-- #1.3 19/712 message/rfc822 --]

From: David Both <dboth@testvm1.both.org>
Message-Id: <202408310153.47V1r5Ka126006@testvm1.both.org>
Date: Fri, 30 Aug 2024 21:53:05 -0400
To: test@example.com
Subject: Test email 1 from testvm1.both.org


[-- #1.3.1 17/682 text/plain, 7bit, us-ascii --]

Hello world
& 

In case you don’t want to read and interpret the bounce message you receive from that little test, it’s saying that the remote host doesn’t accept emails. That portion of the message is, “(reason: 556 Host does not accept mail: MX 0 .)”.

Oh! You can exit the mailx client mode by entering q and pressing Enter.

Things to remember

There are some things to remember about email.

You need a DNS record

Unfortunately, just sending an email from the command line requires a bit more infrastructure to support its ability to send to other email servers. You need a DNS record with one of the service providers such as GoDaddy, Network Solutions, or Squarespace Domains.

It is not instant

One of the most common misconceptions that many end users have about email is that it is instant. It is not. Email may get held up at one of the MTAs for various reasons. Heavy traffic can delay emails and anything marked as bulk in one of the headers will be placed at the bottom of the queue and only sent when all emails with higher precedence have been sent. Any email without a precedence header is considered to be normal. Bulk email is sent from listservs and may have many addressees at any one domain.

I had one situation when working in a government organization where a PHB tried to ream me out and threatened me with some sort of disciplinary action because an email he sent did not get to the people in his building immediately upon being sent. The email he sent was to warn of an imminent tornado which was, in fact, bearing down on that part of the city at the time. But the email was sent to a list and between being bulk mail as well as having hundreds of recipients in an email system that received more than 20,000,000 (yes 20 million) emails per day it took some time to process and deliver of all those emails.

And, as we have mentioned before, one must be sitting at their computer with the email client up and running and watching for new emails to come in for this asynchronous communication system to be effective. Email is just not an appropriate communication method for that type of imminent danger.

There is no delivery guarantee

Another popular misconception is that email will always get delivered. It won’t. Many email systems drop emails that don’t conform to their anti-spam or bulk mail policies. They may reject emails for many reasons and there is nothing that we on the sending end can do about it. Sure, we can call or email the designated contact for the domain but in most cases they ignore this type of complaint.

Emails also get dropped when routers become overburdened and start dropping packets. In this case the sending server may try to send the email again but there is still no guarantee of its ultimate delivery.

And, as we’ve seen in this article, some domains don’t accept email at all.


  1. A makefile is a series of shell commands and variable statements that are used to create a finished project from a group of input files. Although we can use it with SendMail to create very complex configuration files and databases from various ASCII text input files, makefiles can also be used to compile programs using languages such as C. The makefile is the recipe that combines all of the input ingredients into the final product. ↩︎

Leave a Reply