SkillAgentSearch skills...

Envelope

Insert a message and attachments and send e-mail / sign / encrypt contents by a single line.

Install / Use

/learn @CZ-NIC/Envelope
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Envelope

Build Status Downloads

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 gpg and 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-magic after installing envelope which is fully compatible with both projects. Both use libmagic under the hood which is probably already installed. However, if it is not, install sudo apt install libmagic1.

Bash completion

  1. Run: apt install bash-completion jq
  2. Copy: extra/envelope-autocompletion.bash to /etc/bash_completion.d/
  3. 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 --message parameter.)
    • .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 (without alternative and boundary parameter)
    • .text(path=None): Alias of .message (without alternative and boundary parameter)
    • 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.txt
    

    Envelope 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

View on GitHub
GitHub Stars181
CategoryContent
Updated14d ago
Forks18

Languages

Python

Security Score

95/100

Audited on Mar 16, 2026

No findings