mailcellar
Gmail storage full? Move old mail out of Gmail without losing it. mailcellar keeps a local backup of your Gmail accounts. You can then take old mail out of Gmail by rule while the backup keeps it, and it stays searchable, exportable and restorable whenever you need it.
- Back up every account incrementally, in Got Your Back's format; an existing gyb backup carries on where it is.
- Offload old mail by rule, in stages you check: plan, review, label, look in Gmail, then trash. Nothing is ever permanently deleted from Gmail, and the backup is checked for every message before it goes.
- Find and restore it later:
mailcellar searchsearches the backups, offloaded mail included, andmailcellar restoreputs mail back into Gmail, into the same account or another. - Deduplicate, export and report: remove duplicate copies within and across accounts, copy mail out as an mbox or a zip, and see what takes up the space.
It runs on your own computer with your own Google Cloud project: there is no service in between, and your mail goes nowhere but between Gmail and your disk. Setting up the project takes about ten minutes (guide). mailcellar is in beta: it is used on real mailboxes, and its backups are in gyb's fixed format, but commands and options may still change before 1.0. It runs on macOS and Linux and needs Python 3.14, which uv installs for you.
mailcellar setup [ADDRESS] add an account from a downloaded OAuth client
mailcellar backup [ACCOUNT ...] incremental backups in gyb's format
mailcellar count [ACCOUNT ...] compare Gmail with the backup
mailcellar meta [ACCOUNT ...] fill the per-message sidecar for older mail
mailcellar verify [ACCOUNT ...] check that the backup's files are still intact
mailcellar schedule install|status|remove run backups regularly, unattended
mailcellar dedup … find duplicates and remove them from Gmail, in stages
mailcellar offload … take old mail out of Gmail, keeping it in the backup
mailcellar restore ACCOUNT … put backed-up mail back into Gmail
mailcellar export ACCOUNT … copy mail out as an mbox file or a zip of .eml files
mailcellar search QUERY … find mail in the backups, offloaded mail included
mailcellar report … storage, bulk mail, volume, threads, labels, correspondents,
backup health, top senders
mailcellar config where the config and data live; each account's state
backup, count and meta take every configured account unless given
some (an address, a config name like work, or a unique part of an
address). Each command takes --help.
Results go to stdout; progress, warnings and errors go to stderr. Add -v
anywhere on the line to also see Gmail's retries and rate-limit waits (waits
of 10 seconds or more show without it), or -q to see only warnings and
errors.
How it fits together: docs/architecture.md.
Guides
Also on the documentation site, https://mailcellar.github.io/mailcellar/.
- Setting up Google Cloud: the project and OAuth client mailcellar signs in with, and the first consent screen.
- Scheduled backups: run backups regularly, unattended, and what happens when a token needs signing in.
- Migrating from gyb: continue an existing Got Your Back backup instead of starting again.
- Offloading old mail safely: a worked example, from writing a rule to restoring.
- Exporting mail: copy mail out as an mbox or a zip, for a mail client or for someone else.
- Recovering when something goes wrong: an expired token, a long gap between backups, an interrupted run, a lost data root.
- Troubleshooting and FAQ: slow runs,
countresults, chats, weekly sign-in, why not IMAP or Takeout.
Quick start
You need uv (it provides Python 3.14) and a Google account.
- Install.
uv tool install mailcellar # from PyPI; puts the mailcellar command on your PATH
pipx install mailcellarworks too, with Python 3.14. To run it from a clone instead, see Development. - Create an OAuth client. In the Google Cloud console, create a project, enable the Gmail API, set up the OAuth consent screen with yourself as a test user, and create an OAuth client of type Desktop app. Download its JSON. One client can serve several accounts: copy the same JSON into each account's folder. The step-by-step version, including Testing versus In production (Testing tokens expire after 7 days), is Setting up Google Cloud.
- Add the account.
mailcellar setuptakes the downloaded JSON, checks that it is a Desktop app client, saves it as~/.config/mailcellar/<name>/client_secrets.json, lists the account inaccounts.tomland signs in, read-only. It asks for what you don't give:mailcellar setup alex@example.org --client ~/Downloads/client_secret_*.json
It changes nothing in Gmail, and a second run for the same account is harmless (--namechooses the config name,--no-authskips the sign-in,--forcereplaces a different client). To do it by hand, save the JSON and list the account yourself (see Configuration):work = "alex@example.org"
The backups go in~/mailcellar. To keep them somewhere else, such as a larger disk, set it in~/.config/mailcellar/settings.toml:data_dir = "/Volumes/Archive/mailcellar"
- Check, then back up. (After
setupyou are already signed in.)mailcellar config # the config and data folders; the account's client and tokens mailcellar backup work # opens a browser once for Google's consent screen, if not yet mailcellar count work # what Gmail has against what the backup has
The first backup lists every message and downloads it. For a large mailbox that takes a while; if it stops, re-running carries on where it left off. Later backups read Gmail's change history and take seconds.
Back up at least every four weeks. Gmail keeps change history for about four weeks. A backup after a longer gap still works, but it lists the whole mailbox again instead of reading the changes. A monthly or weekly scheduled job is enough, and mailcellar can set one up:
mailcellar schedule install # macOS: a launchd agent, weekly; elsewhere: a cron line
mailcellar schedule status # installed? each account's last backup and token
mailcellar schedule remove
The job runs backup --unattended, which never opens a browser: a token that
needs signing in fails that account's run, with the command to fix it, and is
recorded for report health. See Scheduled backups.
Tokens and the consent screen. If the consent screen's publishing status is Testing, Google expires its tokens after 7 days, and the next backup asks you to sign in again. Either set the status to In production or renew access before it runs out:
mailcellar auth work --scope readonly --renew # or --scope modify for apply and restore
auth asks for consent again (--renew), which starts the 7 days afresh;
without --renew it only signs in if the token no longer works. mailcellar
records when consent was given, shows it in mailcellar config and
report health, and warns when a token is 5 days old or more, printing this
command. It can't see the consent screen's status, so the warning goes by
the time since consent; if your tokens don't expire, turn it off with
token_warn_days = 0 in settings.toml. (mailcellar dedup auth still
works, as an alias.)
What changes Gmail
Everything is read-only except these, and each one asks for confirmation or stages its changes:
| Command | What it changes | Access |
|---|---|---|
dedup apply --label / offload apply --label |
adds a review label to the planned messages | modify |
dedup apply --trash / offload apply --trash |
moves labelled messages to Gmail's Trash | modify |
auth ACCOUNT --scope modify |
grants modify access (changes nothing in the mailbox) | modify |
restore ACCOUNT … --yes |
moves offloaded mail out of Trash, or uploads backed-up mail Gmail no longer has (into this account or, with --to, another), or mail from a pruned batch, an mbox file or another gyb folder; adds a restored/<date> label |
modify |
backup --sync |
the backup: moves mail permanently deleted from Gmail into <data root>/_pruned/ |
read-only |
- Nothing is ever permanently deleted from Gmail. Removals go to Trash, after a review label. Removing the label from a message vetoes it. Gmail empties its Trash after 30 days; until then, a message can be moved back from Trash in Gmail.
- Backups only add.
backup,countandmetanever delete anything. The one exception is--sync, and it moves files to_pruned/rather than deleting them, behind a confirmation and a 10% guard. - Offloaded mail stays in the backup. Once Gmail empties its Trash, the
backup is the only copy, and
restoreuploads it from there.offload apply --trashreports first whether Time Machine covers the data root. Keep a second copy of the data root. - Restore only adds. It deletes nothing, in Gmail or in the backup, and skips what Gmail already has.
Backups need only read access. dedup apply, offload apply and
restore --yes ask for modify access to the account they change.
Configuration
The config folder holds credentials, so keep it private (chmod 700 ~/.config/mailcellar; token files are written owner-only) and out of any
dotfile manager or sync:
~/.config/mailcellar/
accounts.toml # config name → address
settings.toml # optional: data_dir, token_warn_days
<name>/client_secrets.json
<name>/token-readonly.json, token-modify.json # written on first use
# accounts.toml: config name = the account's Gmail or Google Workspace address.
# The name is the folder in the config folder holding that account's OAuth
# files, and what you type on the command line (`mailcellar backup work`).
personal = "alex@example.com"
work = "alex.lee@example.org"
Where things are. mailcellar config shows both folders, where each
setting came from, and every account's OAuth client, tokens, message
count and last backup. It never prints a credential.
- Config folder:
$MAILCELLAR_CONFIG, else~/.config/mailcellar($XDG_CONFIG_HOMEis honoured), else./configin the project, the old place. - Data root: everything derived from mail, that is the backups, the
dedup and offload plans and logs, and
_pruned/. It is$MAILCELLAR_DATA, elsedata_dirinsettings.toml, else~/mailcellar. (It used to default to./datain the folder you ran the command from; a./datathat already holds mailcellar's data is still used until~/mailcellarexists, andmailcellar configsays so.)
~ is expanded; a relative path is taken from the working directory.
# settings.toml
data_dir = "~/data/mailcellar"
token_warn_days = 5 # warn when a token is this many days past consent; 0 = never
To move existing backups, move the whole folder and set the new path. Then
run mailcellar dedup index (it records each backup's folder) and re-run
mailcellar offload plan (its plan holds .eml paths). backup --folder
still overrides the location for one account, but only the data root is
seen by every tool.
Backups
mailcellar backup # every account, incremental
mailcellar backup personal # one account
mailcellar count # compare Gmail with the backups
mailcellar backup personal --full # list every message instead of using history
mailcellar backup --unattended # for scheduled runs: never opens a browser
mailcellar backup personal --sync # also move mail permanently deleted from Gmail
# (not offloaded mail) into <data root>/_pruned/
mailcellar meta # fill meta.sqlite for older mail
mailcellar verify # are the backup's files still intact?
Exit status (for scripts and schedulers): 0 when everything worked. Otherwise 1, in any of these cases:
- an account failed (with several accounts, the others still run);
- downloads failed (the next run fetches them), or
--syncstopped at its guard; countfound mail missing from the backup;verifyfound a problem.
restore exits 1 when any message was skipped or failed.
Checking the backup. Once mail is offloaded and Gmail has emptied its
Trash, the backup holds the only copy, so verify looks for damage that
would otherwise go unnoticed: a failing disk, a sync tool rewriting files,
an accidental delete. It needs no Gmail access and changes nothing (both
databases are opened read-only).
mailcellar verify # every backup, every message
mailcellar verify work --offloaded # only offloaded mail: the copies with no other source
mailcellar verify --sample 500 # 500 random messages: quick enough for a routine check
For each message it checks that the .eml exists and parses, and that its
content hash matches the one meta.sqlite recorded. It also checks that
msg-db.sqlite and meta.sqlite agree on which messages exist, and, with
--offloaded, that every offloaded message is in the backup. Problems are
listed (--top N sets how many) and the exit status is 1 if there are any.
A message with no current meta.sqlite row has nothing to compare with: it
is counted as unchecked, with a warning, and mailcellar meta fills it in.
A full run parses every message, so it takes a while on a large backup;
progress goes to stderr.
Backups live in <data root>/<email>/, in the format of
gyb, so other tools can read
them too. mailcellar restore puts mail back into Gmail.
Removing duplicates
mailcellar dedup index # catalogue the backups
mailcellar dedup match # report duplicate groups
mailcellar dedup plan --keep origin # across accounts: drop forwarded copies
mailcellar dedup plan --scope within # within each account
mailcellar dedup apply # dry run against live Gmail
mailcellar dedup apply --label --limit 5 # label 5 removals for review
mailcellar dedup apply --trash --limit 5 # move labelled ones to Trash
Review the plan (<data root>/dedup/dedup-plan.csv) and the labelled
messages in Gmail before trashing; removing the label vetoes a message.
Each run is logged in <data root>/dedup/dedup-apply-log.csv. How
copies are matched and which one is kept:
docs/architecture.md.
Offloading old mail
Rules go in <data root>/offload/rules.toml, one [[rule]] table each.
The keys are documented in src/mailcellar/offload/rules.py:
[[rule]]
name = "old work mail"
account = "work"
label = "work" # or sender, list, forwarded_from, category, subject, to_me,
# larger_than_mb; different keys must all match
before = "2022-01-01" # or a number of years ago, e.g. "5"
# except = { subject = "contract", to_me = true } # keep what matches any of these
# waive = ["thread"] # drop default protections (sent, starred, thread, replied, labels)
# protect = ["correspondents"]
mailcellar offload plan # all accounts → <data root>/offload/offload-plan.csv
mailcellar offload plan personal --top 30 --csv ~/reports/offload
mailcellar offload plan --review # also a review page per rule
plan changes nothing. It prints what each rule would offload (by year and
sender) and what its protections keep. To keep particular messages, add a
user label in Gmail and run a backup.
For a rule that selects thousands of messages, --review also writes one
HTML page per rule to <data root>/offload/review/ (open it in a browser):
the summary tables, a random sample of what the rule would offload and of
what each protection keeps, the largest messages, the threads with the most
messages in the offload, and attachment types by size. It shows senders
and subjects, never message bodies, and is for you alone: keep it on your
machine. The same plan shows the same sample.
mailcellar offload apply # dry run: Gmail and backup checks
mailcellar offload apply --label --limit 2000 # label the next 2,000 offload-candidate
mailcellar backup personal # trash needs a backup newer than the plan
mailcellar offload apply --trash --limit 2000 # trash the next 2,000 labelled ones
Repeated runs with --limit move on through the plan. Removing the label
in Gmail vetoes a message for good. Trashed messages are recorded as
offloaded, so backup --sync keeps them in the backup after Gmail empties
its Trash.
How long it takes:
- labelling is fast: thousands of messages a minute;
- trashing takes one Gmail call per message, about 4 a second, so 4,500 messages take about 17 minutes;
- run large batches in the background, or in batches with
--limit.
Each trash run writes a manifest,
<data root>/offload/batches/<batch>/offloaded.csv: every message it
offloaded, with its .eml path, date, sender, subject and rule. Every plan
is also kept in offload/plans/, and the apply log names the plan each run
used. To put offloaded mail back, see Restoring mail.
report storage shows, per batch, how much Gmail has freed: the messages
whose Trash has been emptied (as the last backup or count found) and
their size, what is still in Trash and when Gmail will empty it, and what
was restored since. Gmail's own storage figure isn't available through its
API, so the sizes are its per-message estimates.
Restoring mail
restore puts backed-up mail back into Gmail: offloaded messages, or a
whole backup, into its own account or another configured one. Without
--yes it is a dry run, which checks the backup and Gmail and says what
it would do.
mailcellar restore personal --batch 2026-01-15-093000 # dry run of one offload batch
mailcellar restore personal --batch 2026-01-15-093000 --yes
mailcellar restore personal --rule "old work mail" --limit 100 --yes
mailcellar restore personal --id 18c0ffee0000abcd --yes
mailcellar restore personal --offloaded # everything offloaded
mailcellar restore personal --all # the whole backup
mailcellar restore work --all --to personal --label-prefix work # into another account
Batch names are the folders in <data root>/offload/batches/. --limit
takes the oldest messages first, and repeated runs carry on where the
last one stopped.
Narrowing a selection. Any of the selections above can be narrowed, so "last year's mail from one sender" needs no ID lookup first:
mailcellar restore personal --all --after 2025-01-01 --before 2026-01-01 --sender @example.com
mailcellar restore personal --offloaded --has-label projects --sender alex@example.org
--before DATEkeeps mail older than the date,--after DATEmail from that date on. A date isYYYY-MM-DD(UTC) or a number of years ago.--has-label NAMEkeeps mail with that user label, by name, ignoring case (system labels such asINBOXdon't count). It is not--label, which names the label that restored mail gets.--senderkeeps mail from an address, or from any address at a@domain, ignoring case; it goes by the From address, so a relayed message counts as from its relay.--has-labeland--sendercan be repeated: mail matching any one of the values stays.
Everything given has to hold at once, and none of them is a selection by
itself: name --all, --offloaded, --batch, --rule or --id too.
How each message comes back (the first that applies):
- still in Gmail's Trash (within 30 days of the offload): moved out, keeping its ID, labels and thread;
- offloaded, but already out of Trash (moved by hand): recorded and relabelled;
- never offloaded and still in Gmail (with
--all): left alone; - gone, but Gmail has the same Message-ID and content under another ID: recorded as that message;
- gone: uploaded from the backup with its labels, apart from those Gmail won't take (Trash, Spam, chat, superstars) and the offload and dedup labels. The upload keeps the original date; Gmail threads it by its headers.
Restored messages lose the offload label and gain restored/<date>
(--label NAME to choose another), so a restore can be found and undone.
The backup indexes each new Gmail ID, sharing the existing .eml, so the
next backup doesn't download it again. A message whose Message-ID Gmail
already holds with other content is skipped: Gmail would match the
upload to that message instead of storing this one.
Into another account (--to): every message is looked up by
Message-ID there, and new IDs go into that account's backup. It needs
modify access to that account (mailcellar auth ACCOUNT --scope modify). --label-prefix P nests the backed-up user labels under P/;
--strip-labels restores none, so the messages arrive archived with only
the restored/ label.
How long it takes: the dry run checks every .eml file and looks each
message up in Gmail, so on a large backup it takes minutes. Uploads run at
about 6 a second, so the dry run's estimate for 4,500 messages is about 13
minutes and for 50,000 over two hours. Progress lines go to stderr (-q turns them off); run
large restores in the background.
Runs are logged in <data root>/restore/restore-log.csv, and each
restored message is recorded in its backup's meta.sqlite. How it works:
docs/architecture.md.
From elsewhere. Three other sources hold mail that isn't in a backup's
index. Each restores every message it holds, narrowed by --id, --before,
--after, --has-label, --sender and --limit, with the same dry run
and --yes:
mailcellar restore personal --from-pruned 2026-03-01-120000 # what backup --sync moved out
mailcellar restore personal --from-mbox ~/Takeout/Mail/All.mbox --yes
mailcellar restore personal --from-folder /Volumes/old/GYB-GMail-Backup-old@example.org
--from-pruned BATCH: mail thatbackup --syncmoved into<data root>/_pruned/<email>/BATCH/, with the labels in itspruned.csv. It goes back into that account, or another with--to.--from-mbox FILE: a Google Takeout export, or a filemailcellar exportwrote, into ACCOUNT. Labels come from each message'sX-Gmail-Labelsheader (Takeout's names such asInboxorCategory Updatesbecome Gmail's own; itsOpenedandArchivedmarkers are not labels), and that header andX-GM-THRIDare taken off before upload. In the log the messages arembox-1,mbox-2, … in file order.--from-folder DIR: a gyb backup folder from elsewhere (another machine, an old account), into ACCOUNT. It is only read.
None of these has Gmail IDs that mean anything in the account restored
into, so each message is looked up there by Message-ID and content, as
with --to: recorded if Gmail has it, uploaded otherwise. Nothing is
recorded in a backup or indexed: a run again finds what was restored by
its Message-ID, and the next backup downloads it.
Exporting mail
Sometimes mail needs to go somewhere other than back into Gmail: to an
accountant or a lawyer, or into a desktop mail client to read a year of
offloaded mail. export copies a selection out of the backup. It is
read-only (nothing changes in Gmail or the backup) and needs no Gmail access.
mailcellar export personal --offloaded --to ~/old-mail.mbox # for a mail client
mailcellar export personal --all --after 2025-01-01 --before 2026-01-01 \
--sender @example.com --to ~/for-the-accountant.zip # the .eml files and an index
The selection is restore's: --batch, --rule, --id, --offloaded or
--all, narrowed with --before, --after, --has-label and --sender
(see Restoring mail), and --limit takes the oldest first.
Mail that has been restored is included, once.
.mboxholds one message after another, each preceded by anX-Gmail-Labelsheader with its labels (comma-separated, as Google Takeout writes it), in the usual mboxrd form: a line starting withFromis written with a>before it. Messages are otherwise as stored..zipholds the.emlfiles under their paths in the backup (<year>/<month>/<day>/<id>.eml) andindex.csvwith each message's date (UTC), sender, subject, labels, Gmail ID and file. A cell that begins with=,+,-or@gets a leading', so a spreadsheet doesn't run a subject as a formula.
The file is written under another name and renamed when it is complete, so an
interrupted export leaves nothing that looks finished. It refuses a file that
already exists, and a place inside the backup. A message whose .eml file is
missing from the backup is left out and reported, and the exit status is 1:
mailcellar verify shows what is missing.
An export is a copy of your mail, outside the backup: keep it, and delete it, with the same care. The Exporting mail guide has worked selections and what to do with the result.
Searching mail
Gmail's search no longer finds mail once it has been offloaded. search
finds mail in the backups, offloaded or not, by words in the sender,
recipients, subject and body (not attachments). It is read-only towards
Gmail and the backups, and needs no Gmail access.
mailcellar search "invoice 2024" # every backup
mailcellar search "from:alex subject:contract" work # one backup
mailcellar search '"quarterly figures"' --offloaded --after 2020-01-01
Every word must be found, whole and ignoring case and accents. A
"phrase" must be found as written; from:, to: and subject: look only
in that field (from:example.org finds a domain); OR between two words
takes either; -word leaves out mail with that word (after -- if the query
starts with one); and word* matches words starting with it. Narrow with
--offloaded, --rule, --batch, --after and --before.
Results are newest first, at most 50 (--limit): the date, sender, subject
and .eml file, and for offloaded mail the mailcellar restore … --id
command that puts it back. The exit status is 1 when nothing matches.
The index is <data root>/search/search.sqlite. Each search first adds new
and changed mail to it for the backups searched, so the first search reads
every message once and takes a while; later ones read only what changed
(--no-update skips that). It holds what is needed to find a message, not
the text itself, so the results show where to look and the .eml file
holds the message. Deleting the file is safe: the next search builds it
again.
Reports
mailcellar report storage # what takes up space; space freed per offload batch
mailcellar report storage personal --csv ~/reports/storage
mailcellar report bulk # mailing lists and bulk senders; unsubscribe candidates
mailcellar report volume # received, sent and forwarded mail over time
mailcellar report threads # thread sizes; threads in both accounts
mailcellar report labels # user labels per account; unlabelled mail
mailcellar report correspondents # who you write to and hear from; reply rates
mailcellar report health # backup completeness, runs, gaps, pruned batches
mailcellar report senders personal --top 30 # top senders and domains in one backup
Reports read only the local backups, never Gmail. Each takes --help,
and prints notes on what its columns mean.
Development
To run mailcellar from a clone, with the tests and tools:
git clone https://github.com/mailcellar/mailcellar.git
cd mailcellar
uv sync # the dependencies, and mailcellar in editable mode
uv run mailcellar config # every command, run from the clone
uv run pytest # all tests; no network, never the real config or data
uv run pytest --cov # the same, with a branch-coverage report
uv run ruff format && uv run ruff check
The code is one package, src/mailcellar/: cli.py dispatches to
backup/, dedup/, offload/, restore/ and report/, which share paths.py,
gmailapi.py and message.py. uv sync installs it in editable mode;
python -m mailcellar works too. See
docs/architecture.md.
How to contribute, and the rules changes follow: CONTRIBUTING.md.
Acknowledgements
mailcellar's backups use the on-disk format of Got Your Back (gyb) by the GAM team, so backups made by either tool can be read by the other. mailcellar is a separate project and shares no code with gyb.
mailcellar is not affiliated with or endorsed by Google or the gyb project. Gmail and Google Workspace are trademarks of Google LLC.
License
Metadata
Release files for mailcellar 0.10.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mailcellar-0.10.0.tar.gz | 257.8 kB | With provenance | Details for mailcellar-0.10.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mailcellar-0.10.0-py3-none-any.whl | Python 3 | none | any | Details for mailcellar-0.10.0-py3-none-any.whl |
Total release size: 433.9 kB
Release files / mailcellar-0.10.0.tar.gz
| Download URL | mailcellar-0.10.0.tar.gz |
|---|---|
| Size | 257.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bb30d89b18b4a6b2fde24fd0d997c8767ca621bfc00036feccd74cb04fc0b7b7
|
|
BLAKE2b-256 checksum How to use checksums |
2fa9f0b9a50bf335cda9365a1b91a921a84120928e5afea9b60df9c7a6fc72a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / mailcellar-0.10.0-py3-none-any.whl
| Download URL | mailcellar-0.10.0-py3-none-any.whl |
|---|---|
| Size | 176.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
28cee01bd59fc580c8df9a7d56759ddeedd069d66210a24c89c0153cb18662ce
|
|
BLAKE2b-256 checksum How to use checksums |
21d69a75f6c9e636f6e8f3be920144049c40085ad79117cd8b35e86624612084
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logSecurity for mailcellar 0.10.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for mailcellar-0.10.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.