CLI SMTP client in pure Python. No dependencies, one command: it builds a
UTF-8 text/plain message — text/html with --html,
multipart/mixed once files are attached — and hands it to an SMTP
server.
python3 -m pip install --user --upgrade sendsmtpRequires Python 3.11 or newer.
$ sendsmtp smtp.example.com me@example.com you@example.com -s "Hi" -m "Hello!"
Message successfully sent.sendsmtp [-h] [-m MESSAGE] [-i INPUT] [--html] [-p PORT] [-u USERNAME]
[--password PASSWORD] [-t | --starttls] [--allow-untrusted]
[-c CC] [-b BCC] [-s SUBJECT] [-a PATH] [-v]
HOST FROM TOHostname or IP address of the SMTP server to connect to.
$ sendsmtp smtp.example.com me@example.com you@example.com -m "hi"Sender address, used both as the SMTP envelope sender (MAIL FROM) and
as the From: header.
Recipient address, or several addresses separated by commas — no spaces around the commas.
$ sendsmtp smtp.example.com me@example.com "a@example.com,b@example.com" -m "hi"Message body, given inline.
$ sendsmtp smtp.example.com me@example.com you@example.com -m "Deploy finished."Path to a file to read the message body from. Takes precedence over
--message. If the path is not an existing file the option is ignored
and the body is taken from --message or from stdin instead.
$ sendsmtp smtp.example.com me@example.com you@example.com -i report.txtIf neither --message nor --input is given, the body is read from
stdin. Piped input is read to EOF:
$ dmesg | tail -n 20 | sendsmtp smtp.example.com me@example.com you@example.com -s "dmesg"When stdin is a terminal, sendsmtp prompts and reads lines until a line
containing only EOF:
$ sendsmtp smtp.example.com me@example.com you@example.com
Please, provide message contents. Type 'EOF' for end.
First line.
Second line.
EOF
Message successfully sent.Send the body as text/html instead of text/plain. The body itself
is taken from --message, --input or stdin as usual — the flag only
changes the content type, nothing is escaped or wrapped.
$ sendsmtp smtp.example.com me@example.com you@example.com \
-s "Report" -i report.html --htmlNo plain-text alternative part is generated: the message is a single
text/html part, so clients that refuse HTML show it as markup.
Message subject.
$ sendsmtp smtp.example.com me@example.com you@example.com -s "Nightly build" -m "green"If --subject is not given and the body starts with a Subject:
line, that line is stripped from the body and used as the subject:
$ printf 'Subject: From the body\n\nBody text.\n' \
| sendsmtp smtp.example.com me@example.com you@example.comSMTP port. Defaults depend on the security mode: 25 for plain,
587 with --starttls, 465 with --tls.
$ sendsmtp smtp.example.com me@example.com you@example.com -p 2525 -m "hi"Use implicit TLS — the connection is encrypted from the first byte
(SMTPS, port 465 by default). Mutually exclusive with --starttls.
$ sendsmtp smtp.example.com me@example.com you@example.com -t -u me@example.com -m "hi"Connect in plain text and upgrade the connection with the STARTTLS
extension (port 587 by default). Mutually exclusive with --tls.
$ sendsmtp smtp.example.com me@example.com you@example.com --starttls -u me@example.com -m "hi"Skip TLS certificate verification: the server certificate is not checked
against the trust store and its hostname is not matched. Only affects
--tls and --starttls. Insecure — anyone on the path can
impersonate the server — so use it only for servers with a self-signed
certificate you cannot add to the system trust store.
$ sendsmtp smtp.internal me@example.com you@example.com --starttls --allow-untrusted -m "hi"Username for SMTP authentication. Without it no AUTH is attempted.
Password for SMTP authentication. If --username is given but
--password is not, the password is asked for interactively and is not
echoed — preferable, since command lines are visible to other processes
and land in the shell history.
$ sendsmtp smtp.example.com me@example.com you@example.com --starttls -u me@example.com -m "hi"
me@example.com's passwd:Authentication failures abort the run; the message is not sent.
Carbon-copy recipient(s), comma separated. The addresses appear in the
CC: header and receive the message.
$ sendsmtp smtp.example.com me@example.com you@example.com -c "boss@example.com" -m "hi"Blind carbon-copy recipient(s), comma separated. They receive the message but are not listed in any header.
$ sendsmtp smtp.example.com me@example.com you@example.com -b "archive@example.com" -m "hi"Attach a file to the message. Repeat the option once per file; the message
then becomes multipart/mixed with the body as its first part.
$ sendsmtp smtp.example.com me@example.com you@example.com \
-s "Nightly report" -m "See attached." -a report.pdf -a data.csvThe content type is guessed from the file name, falling back to
application/octet-stream. A missing path is reported before the SMTP
connection is opened, so nothing is sent and no password is asked for.
Print the SMTP dialog to stderr, report the connection and authentication steps, list the addresses the message was delivered to, and, on failure, let the full stacktrace through instead of a one-line error.
$ sendsmtp smtp.example.com me@example.com you@example.com -m "hi" -v
Connected to smtp.example.com:25 (plain).
send: 'ehlo host.example.com\r\n'
reply: b'250 smtp.example.com\r\n'
...
Message successfully sent to you@example.comPrint the usage summary and exit.
The generated message carries From:, To:, Subject:,
CC: (only with --cc) and X-Mailer: sendsmtp.
| Code | Meaning |
|---|---|
0 |
Message accepted by the server for every recipient. |
1 |
Error, or at least one recipient was refused. |
130 |
Interrupted with Ctrl-C. |
On failure only a single-line error is printed; pass --verbose to get
the SMTP dialog and the full stacktrace.
MIT. See LICENSE.