Recovering when something goes wrong¶
What to do, case by case, when a run fails or something is lost. Each case says what you see, what it means, and what to do. None of the first three needs more than re-running a command; the fourth is about the data root itself, and the fifth about a leaked credential.
The commands below are dry runs or only add to the backup unless they say otherwise. A failed run leaves the backup as it was, apart from what it had already saved.
A token expired or was revoked¶
What you see. A command that talks to Gmail prints, then opens your browser:
Stored readonly token for work@example.org was rejected (...); authorising again.
(modify in place of readonly for dedup apply, offload apply and
restore --yes.)
What it means. Google no longer accepts the saved token. Either you revoked access, or the Google Cloud project's consent screen is in Testing status, where Google expires tokens after 7 days. See Setting up Google Cloud.
What to do. Nothing is lost. Sign in as the account in the browser and tick the Gmail permission; the command then carries on. On a machine with no browser, or from a scheduled job, authorise ahead of time:
mailcellar auth ACCOUNT --scope readonly # for backup, count, meta, reports
Apply and restore --yes sign in for modify access each time they run, so
they need a browser; with keep_modify_token = true in settings.toml,
mailcellar auth ACCOUNT --scope modify stores that access ahead of time
instead.
auth changes nothing in the mailbox and takes every account if none is
named. (It used to be mailcellar dedup auth, which still works.) To avoid
the error, renew a token that is getting old before it runs out: add
--renew, which asks for consent again and starts Google's 7 days afresh.
mailcellar warns when a token is 5 days past consent, and mailcellar config
and report health show how old each one is. If it ends with Google did not grant gmail.…, the Gmail
permission box was not ticked; delete the token file it names, in the
account's folder in the config folder, and run it again. To stop the weekly
sign-in, publish the app (In production) as the Google Cloud guide
describes.
More than four weeks since the last backup¶
What you see.
Gmail no longer has history back to the last run; listing every message instead.
What it means. Gmail keeps its change history for about four weeks. A
backup normally reads only the changes since the last run. After a longer
gap, that history is gone, so the run lists every message in the account
instead. It is slower, mostly the listing, but it is safe: it downloads
only the messages the backup does not already hold, and it deletes nothing.
The same listing happens on the first run in a folder and with --full.
What to do. Let it finish. If it stops partway, run it again; it
carries on, since messages already saved are skipped. The history position
is stored only after a run with no failed downloads, so a failed run is
repeated in full next time, not skipped. A scheduled backup at least every
four weeks avoids all of this: mailcellar schedule install sets one up (see
Scheduled backups).
An interrupted offload or restore¶
Both record each message as they go, so an interruption (a crash, a lost connection, closing the terminal) is safe to follow with the same command.
offload apply --trash. Run it again, with the same options. Messages
the interrupted run had already trashed but not recorded are found (they are
in Trash, still carry the label, and are not yet recorded) and recorded
after the same backup checks, and the rest of the plan carries on. It says
Recorded N messages an earlier run trashed without recording. A dry run
(offload apply) reports them without recording. The labelling stage,
--label, can simply be repeated.
restore --yes. Run it again. Each message is recorded in the backup's
meta.sqlite as it succeeds, and the next run leaves alone what is already
back, looking each message up in Gmail again; one restored but deleted
since goes back again. Gmail matches an upload to the
message that already holds its Message-ID, so a retried upload returns the
same message, not a second copy. The one exception is a message with no
Message-ID header; the dry run flags those, because a crash during their
upload can leave a duplicate. Mail restored but not yet indexed when the run
died is picked up by the next backup, which downloads it.
backup. Run it again; see the previous case.
To check afterwards, use mailcellar count ACCOUNT and, for an offload,
the batch's manifest in <data root>/offload/batches/.
A damaged or lost data root¶
The data root holds the backups (<email>/msg-db.sqlite, meta.sqlite and
the .eml files), mailcellar's plans and logs, and the dedup index. What
you can rebuild depends on what is left.
You have a copy of the data root (a second disk, Time Machine,
whatever you set up). Restore the whole folder from it, as it was, to where
mailcellar config says the data root is; do not mix files from the copy
with files from the damaged folder. Then:
mailcellar config # the folder is found; each account's state looks right
mailcellar backup # catches up with what Gmail gained since the copy
mailcellar meta # fills meta.sqlite for anything it lacks
mailcellar dedup index # rebuilds the dedup index
mailcellar count # compare Gmail with the backup
backup after an older copy reads Gmail's history from where the copy
stopped, or lists everything if that is more than four weeks ago; either
way it catches up. dedup.sqlite is only an index, so dedup index
rebuilds it from the backups.
One thing an older copy cannot know: mail you offloaded after the copy
was made. Those messages are in the backup (they were downloaded earlier)
but not recorded as offloaded, so once Gmail has emptied its Trash,
forget --deleted would offer to take them out of the backup as if you had
deleted them. Do not confirm that. Read what
backup and count say, and compare against the batch manifests if you
kept them, before using --deleted.
Only some files are damaged. mailcellar verify lists them: files that
are missing, do not parse or no longer match their recorded content hash,
and offloaded mail missing from the index (--offloaded checks just that
mail, which has no other source). It changes nothing.
- A missing or unreadable
.emlfile:backupdownloads it again while the message is in Gmail; the backup counts a message as present only if its file exists. - A damaged or deleted
meta.sqlite:mailcellar metarebuilds the parsed fields from the.emlfiles. It cannot rebuild the records of what was offloaded or restored (the batch manifests inoffload/batches/keep a readable copy of the offloads, but nothing reads them back in). Restore the file from a copy if you have one. - A damaged
msg-db.sqlite, the gyb index, is the hardest case. Restore it from a copy together with its.emlfiles. - Mail that
forgettook out is held in<data root>/_forgotten/untilforget --emptydeletes it, at least 30 days later;mailcellar forget ACCOUNT --undo RUNputs a run back into the backup. Mail an olderbackup --prunemoved out is in<data root>/_pruned/, one folder per run; for this release,mailcellar restore ACCOUNT --from-pruned BATCHputs it back into Gmail. A Google Takeout export, or another gyb folder, can be restored with--from-mboxor--from-folder(see Restoring mail). - Plans and logs are only working files. Make a new plan with
dedup planoroffload plan.
What is lost without a copy. Mail that is still in Gmail is not lost: a
new backup downloads it again, once you move the account's hash chain
anchor (<config>/anchors/<email>.json) aside, since backup won't start
afresh where it has backed up before. Mail that was offloaded exists only in
the backup once Gmail has emptied its Trash, 30 days after the offload. If
the backup is lost and there was no other copy, that mail is gone. Within
the 30 days, open Gmail's Trash and move the messages back by hand. This is
the reason offload apply --trash reminds you to keep a second copy of the
data root, and why you should.
mailcellar export is one way to keep such a copy: it writes a selection
(for example --offloaded) as an mbox file or a zip of .eml files, without
touching the backup. It is a copy of your mail, so store it as carefully as
the data root. See Exporting mail.
A leaked token or client_secrets.json¶
Revoke access, delete the token files and, if the client's secrets leaked too, delete the OAuth client and make a new one. The steps are in SECURITY.md, together with how to report a vulnerability. Nothing in the backup needs changing.