- Go 99.8%
- Pkl 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
git.sr.ht is being decommissioned. The Forgejo instance serves the go-import meta tag, so tag-based 'go get' keeps working under the new path. Docs updated to match. |
||
| .builds | ||
| cmd/migadu | ||
| internal | ||
| .gitignore | ||
| .golangci.toml | ||
| alias.go | ||
| alias_test.go | ||
| context_test.go | ||
| CONTRIBUTING.md | ||
| domain.go | ||
| forwarding.go | ||
| forwarding_test.go | ||
| go.mod | ||
| go.sum | ||
| go.tool.mod | ||
| go.tool.sum | ||
| hk.pkl | ||
| identity.go | ||
| identity_test.go | ||
| LICENSE.md | ||
| mailbox.go | ||
| mailbox_test.go | ||
| migadu.go | ||
| migadu_test.go | ||
| mise.toml | ||
| ratelimit_test.go | ||
| README.md | ||
| rewrite.go | ||
| rewrite_test.go | ||
| settings.go | ||
| settings_test.go | ||
| timeout_test.go | ||
| transport_test.go | ||
| types.go | ||
| types_test.go | ||
Migadu
CLI for Migadu and Go-package for interacting with Migadu.
This project is not endorsed or affiliated by Migadu-Mail GmbH.
Install CLI
Using go:
go install src.timharek.no/tim/migadu@latest
Using Homebrew
brew tap timharek/tap
brew install migadu
Using pre-compiled binary
Select the version you want to install available releases and download
it and add it to your bin or something similar.
Example:
wget https://src.timharek.no/tim/migadu/releases/download/<release>/migadu-<version>-linux-amd64.tar.gz
tar xf migadu-<version>-linux-amd64.tar.gz
cd migadu-<version>
cp migadu /usr/local/bin
Usage
# Configure your user
migadu user add
# Get help
migadu --help
# Listing all mailboxes for default domain
migadu mailbox list
# Listing all mailboxes for a domain
migadu mailbox list --domain example.org
# The IMAP/POP/SMTP settings an email client needs, for one mailbox
migadu settings admin
Creating and updating
Anything you create or update opens in $EDITOR by default, as a commented
TOML buffer that explains every field, and asks before it sends anything:
# Opens a buffer, shows what it would create, asks, then creates it
migadu mailbox create
# The buffer for an update is the mailbox as it is now. Only the keys you
# change are sent
migadu mailbox update admin
Saving and exiting the editor brings up the confirmation:
- May send: yes
+ May send: no
Apply? [y/N/e=edit again/q=quit]
e reopens the buffer with your edits still in it, which is also what a buffer
that does not parse offers. Emptying the buffer, or answering anything but y,
sends nothing at all.
Passing flags is how you skip the editor and do it in one line, which is what a script wants:
migadu mailbox create --local admin --password-method invitation \
--password-recovery tim@example.org
The rules, in short:
- No flags, and a terminal to open an editor in:
$EDITOR. - Any flag: no editor.
--edit: the editor, with the flags filled in for you first.--no-edit, or no terminal, such as in a script or CI: flags only.
VISUAL is used before EDITOR, and vi if neither is set.
As a package
import (
"context"
"src.timharek.no/tim/migadu"
)
func whatever(ctx context.Context) {
// User and token fall back to MIGADU_USER and MIGADU_USER_TOKEN.
c, err := migadu.New(migadu.Credentials{})
// Credentials are who you are; options are how the client talks.
c, err = migadu.New(migadu.Credentials{},
migadu.WithBaseURL(srv.URL+"/v1"), // another API root, such as a test server
migadu.WithTimeout(10*time.Second), // per request, on top of the context's deadline
migadu.WithHTTPClient(client), // or bring your own transport entirely
migadu.WithUserAgent("my-app/1.0"), // "" sends none at all
migadu.WithLogger(log.Printf), // "GET url -> 200 OK" per request
)
// Every call takes a context and honours its cancellation. Without a
// WithTimeout of your own, requests give up after migadu.DefaultTimeout.
domains, err := c.Domains.List(ctx)
// Everything living under one domain is reached through a scope.
d := c.Domain("example.org")
mailboxes, err := d.Mailbox.List(ctx)
identities, err := d.Identity.List(ctx, "admin")
forwardings, err := d.Forwarding.List(ctx, "admin")
rewrites, err := d.Rewrite.List(ctx)
// Migadu's generic client settings are constants, so no call is made.
settings := migadu.ClientSettings("admin@example.org")
// Updates only send the fields they are given.
_, err = c.Domains.Update(ctx, "example.org", migadu.DomainUpdate{
GreylistingEnabled: new(false),
})
// A failure the API explained is an *APIError, which is also how a rate
// limit says how long to wait.
var apiErr *migadu.APIError
if errors.As(err, &apiErr) && apiErr.IsRateLimited() {
time.Sleep(apiErr.RetryAfter)
}
// Use the data
}
Contributing
Anyone can contribute to Migadu. Please refer to the contribution guidelines.
Open pull requests on the forge, report bugs on the issue tracker.