Karl.Cli 1.3.2

dotnet tool install --global Karl.Cli --version 1.3.2
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Karl.Cli --version 1.3.2
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Karl.Cli&version=1.3.2
                    
nuke :add-package Karl.Cli --version 1.3.2
                    

Karl.Cli

Karl includes a standalone CLI tool for:

  • Sending test emails
  • Rendering templates
  • Local development workflows
  • CI/CD pipelines
  • Administrative scripts

Installing Karl.Cli

dotnet tool install --global Karl.Cli

Or locally:

dotnet new tool-manifest
dotnet tool install Karl.Cli

Basic Usage

Send an Email

karl send \
  --from noreply@example.com \
  --smtp-host smtp.example.com \
  --to user@example.com \
  --subject "Hello" \
  --body "# Hello World"

CLI Configuration Sources

Karl.Cli reads configuration from:

  • --json <path> when provided explicitly
  • Local config files in current directory (first match wins): .karl, karl, karl.json
  • User config directory:
    • Windows: %USERPROFILE%/.karl
    • Linux/macOS: $XDG_CONFIG_HOME/karl or ~/.config/karl
  • Environment variables prefixed with KARL_

Use __ in environment variable names for nested keys, for example:

KARL_Karl__Smtp__Host=smtp.example.com
KARL_Karl__Smtp__Port=587
KARL_Karl__Smtp__SecurityMode=StartTlsRequired

Configuration Precedence

For Karl:Smtp:*/Karl:File:* settings, a command-line flag always wins over a config file value, and a config file value always wins over Karl.Cli's own built-in defaults:

Setting CLI flag Config key Built-in default
SMTP host --smtp-host Karl:Smtp:Host none — see below
SMTP port --smtp-port Karl:Smtp:Port 587
SMTP username --username Karl:Smtp:Username (none)
SMTP password --password Karl:Smtp:Password (none)
STARTTLS mode --tls Karl:Smtp:SecurityMode StartTlsRequired
File output directory --output Karl:File:DirectoryPath emails
File name prefix (none) Karl:File:FileNamePrefix email

send requires an SMTP host to be specified somewhere — via --smtp-host, Karl:Smtp:Host in a config file, or KARL_Karl__Smtp__Host — and fails fast with a clear error if none of them supply one, rather than silently attempting to connect to a default host.

Send Using a Template

karl send \
  --from noreply@example.com \
  --smtp-host smtp.example.com \
  --to user@example.com \
  --subject "Welcome {{name}}" \
  --markdown ./welcome.md \
  --model ./model.json

SMTP Send Example

karl send \
  --from noreply@example.com \
  --to user@example.com \
  --subject "SMTP test" \
  --body "Sent via Karl CLI" \
  --smtp-host smtp.example.com \
  --smtp-port 587 \
  --username username \
  --password password \
  --tls StartTlsRequired

Mass Email Using a CSV File

send, file, and preview all accept --csv to send one personalized email per row of a CSV file instead of a single message. Every CSV value is a string that can be substituted into --subject/--body/--markdown templates — this is token replacement, not typed data binding.

karl send \
  --from noreply@example.com \
  --smtp-host smtp.example.com \
  --csv contacts.csv \
  --to-column Email \
  --name-column Name \
  --subject "Welcome {{FirstName}}" \
  --markdown ./welcome.md
Email,FirstName,Name
alice@example.com,Alice,Alice Smith
bob@example.com,Bob,Bob Jones
  • --to-column (required with --csv) names the CSV column holding the recipient's email address.
  • --name-column (optional) names the CSV column holding the recipient's display name. If omitted, or blank for a row, the email address is used with no display name.
  • --to and --model cannot be combined with --csv — the recipient and the per-row template values both come from the CSV.
  • A row with a blank --to-column value is skipped, not sent. Failed sends are logged and counted, and the batch continues to the next row. A summary line reports the outcome: Sent 48 of 50 emails from contacts.csv (1 skipped, 1 failed).

Token names are case-sensitive and must match the CSV header (or --model JSON property) exactly — a column named FirstName only satisfies {{FirstName}} in a template, not {{firstname}} or {{first_name}}.

Attachments

send, file, and preview all accept a repeatable --attach/-a option to attach one or more local files:

karl send \
  --from noreply@example.com \
  --smtp-host smtp.example.com \
  --to user@example.com \
  --subject "Your invoice" \
  --markdown ./invoice.md \
  --attach ./invoice.pdf \
  -a ./terms.pdf
  • The display name and content type are inferred from each path (invoice.pdf becomes application/pdf); unrecognized extensions fall back to application/octet-stream.
  • A missing --attach path fails the whole command before anything is sent or rendered, the same as a missing --markdown/--model/--csv path.
  • --attach composes with --csv: the same set of attached files is sent with every row's personalized message.
  • file and preview only list attachment names and content types in their output — they don't copy the attached bytes anywhere. Use send against a test SMTP server to verify the actual file contents.

File Output Mode

karl file \
  --from noreply@example.com \
  --to user@example.com \
  --subject "File output test" \
  --body "This message is written to disk." \
  --output ./mail-output

Written files are named with an email prefix by default (e.g. email_20260810_123456_789.txt). There is no --file-name-prefix flag; set Karl:File:FileNamePrefix in a config file to change it.

StdOut Mode

karl preview \
  --from noreply@example.com \
  --to user@example.com \
  --subject "Preview test" \
  --body "This message is printed to stdout."
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.3.2 108 8/10/2026
1.3.1 111 8/5/2026
1.3.0 101 8/5/2026
1.2.0 114 8/3/2026