Envelope
Insert a message and attachments and send e-mail / sign / encrypt contents by a single line.
Install / Use
/learn @CZ-NIC/EnvelopeREADME
Envelope
Quick layer over python-gnupg, cryptography, M2Crypto, smtplib, magic and email handling packages. Their common use cases merged into a single function. Want to sign a text and tired of forgetting how to do it right? You do not need to know everything about GPG or S/MIME, you do not have to bother with importing keys. Do not hassle with reconnecting to an SMTP server. Do not study various headers meanings to let your users unsubscribe via a URL. You insert a message, attachments and inline images and receive signed and/or encrypted output to the file or to your recipients' e-mail. Just single line of code. With the great help of the examples below.
Envelope("my message")
.subject("hello world")
.to("example@example.com")
.attach(file_contents, name="attached-file.txt")
.smtp("localhost", 587, "user", "pass", "starttls")
.signature()
.send()
# Inline image
Envelope("My inline image: <img src='cid:image.jpg' />")
.attach(path="image.jpg", inline=True)
# Load a message and read its attachments
Envelope.load(path="message.eml").attachments()
# in bash: envelope --load message.eml --attachments
Installation
-
Install with a single command from PyPi
pip3 install envelope- Or install current GitHub master
pip3 install git+https://github.com/CZ-NIC/envelope.git- Or just download the project and launch
python3 -m envelope
-
If planning to sign/encrypt with GPG, assure you have it on the system with
sudo apt install gpgand possibly see Configure your GPG tutorial. -
If planning to use S/MIME, you might be required to ensure some prerequisites, ex:
sudo apt install build-essential libssl-dev libffi-dev python3-dev cargo pkg-config -
If planning to send e-mails, prepare SMTP credentials or visit Configure your SMTP tutorial.
-
If your e-mails are to be received outside your local domain, visit DMARC section.
-
Package python-magic is used as a dependency. Due to a well-known name clash with the file-magic package, in case you need to use the latter, don't worry to run
pip uninstall python-magic && pip install file-magicafter installing envelope which is fully compatible with both projects. Both uselibmagicunder the hood which is probably already installed. However, if it is not, installsudo apt install libmagic1.
Bash completion
- Run:
apt install bash-completion jq - Copy: extra/envelope-autocompletion.bash to
/etc/bash_completion.d/ - Restart terminal
Usage
As an example, let's produce in three equal ways an output_file with the GPG-encrypted "Hello world" content.
CLI
Launch as a CLI application in terminal, see envelope --help
envelope --message "Hello world" \
--output "/tmp/output_file" \
--from "me@example.com" \
--to "remote_person@example.com" \
--encrypt-path "/tmp/remote_key.asc"
Module: fluent interface
Comfortable way to create the structure if your IDE supports autocompletion.
from envelope import Envelope
Envelope().message("Hello world")\
.output("/tmp/output_file")\
.from_("me@example.com")\
.to("remote_person@example.com")\
.encrypt(key_path="/tmp/remote_key.asc")
Module: one-liner function
You can easily write a one-liner function that encrypts your code or sends an e-mail from within your application when imported as a module. See pydoc3 envelope or documentation below.
from envelope import Envelope
Envelope(message="Hello world",
output="/tmp/output_file",
from_="me@example.com",
to="remote_person@example.com",
encrypt="/tmp/remote_key.asc")
Documentation
Both envelope --help for CLI arguments help and pydoc3 envelope to see module arguments help should contain same information as here.
Command list
All parameters are optional.
- --param is used in CLI
- .param(value) denotes a positional argument
- .param(value=) denotes a keyword argument
- Envelope(param=) is a one-liner argument
Any attainable contents
Whenever any attainable contents is mentioned, we mean plain text, bytes or stream (ex: from open()). In module interface, you may use a Path object to the file. In CLI interface, additional flags are provided instead.
If the object is not accesible, it will immediately raise FileNotFoundError.
Envelope().attach(path="file.jpg")
# Could not fetch file .../file.jpg
# FileNotFoundError: [Errno 2] No such file or directory: 'file.jpg'
Input / Output
-
message: Message / body text. If no string is set, message gets read. Besides, when "Content-Transfer-Encoding" is set to "base64" or "quoted-printable", it gets decoded (useful when quickly reading an EML file content
cat file.eml | envelope --message).- --message: String. Empty to read.
- --input: (CLI only) Path to the message file. (Alternative to the
--messageparameter.) - .message(): Read current message in
str. - .message(text): Set the message to any attainable contents.
- .message(path=None, alternative="auto", boundary=None)
path: Path to the file.alternative: "auto", "html", "plain" You may specify e-mail text alternative. Some e-mail readers prefer to display plain text version over HTML. By default, we try to determine content type automatically (see mime).print(Envelope().message("He<b>llo</b>").message("Hello", alternative="plain")) # (output shortened) # Content-Type: multipart/alternative; # boundary="===============0590677381100492396==" # # --===============0590677381100492396== # Content-Type: text/plain; charset="utf-8" # Hello # # --===============0590677381100492396== # Content-Type: text/html; charset="utf-8" # He<b>llo</b>- boundary: When specifying alternative, you may set e-mail boundary if you do not wish a random one to be created.
- .body(path=None): Alias of
.message(withoutalternativeandboundaryparameter) - .text(path=None): Alias of
.message(withoutalternativeandboundaryparameter) - Envelope(message=): Any attainable contents
Equivalents for setting a string (in Python and in Bash).
Envelope(message="hello") == Envelope().message("hello")envelope --message "hello"Equivalents for setting contents of a file (in Python and in Bash).
from pathlib import Path Envelope(message=Path("file.txt")) == Envelope(message=open("file.txt")) == Envelope.message(path="file.txt")envelope --input file.txtEnvelope is sometimes able to handle wrong encoding or tries to print out a meaningful warning.
# Issue a warning when trying to represent a mal-encoded message. b ="€".encode("cp1250") # converted to bytes b'\x80' e = Envelope(b) repr(e) # WARNING: Cannot decode the message correctly, plain alternative bytes are not in Unicode. # Envelope(message="b'\x80'") # When trying to output a mal-encoded message, we end up with a ValueError exception. e.message() # ValueError: Cannot decode the message correctly, it is not in Unicode. b'\x80' # Setting up a
Related Skills
docs-writer
99.6k`docs-writer` skill instructions As an expert technical writer and editor for the Gemini CLI project, you produce accurate, clear, and consistent documentation. When asked to write, edit, or revie
model-usage
341.8kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
ddd
Guía de Principios DDD para el Proyecto > 📚 Documento Complementario : Este documento define los principios y reglas de DDD. Para ver templates de código, ejemplos detallados y guías paso
arscontexta
2.9kClaude Code plugin that generates individualized knowledge systems from conversation. You describe how you think and work, have a conversation and get a complete second brain as markdown files you own.
