posted by VaelMail · 8 October 2026
what we store. and why.
your account, mail, security and payments. the actual fields, the reason for each, and how they’re protected.
checked against the running storage configuration and current code on 8 october 2026. names in code are database fields or keys inside a stored record. optional records exist only when you use the feature.
first, what “encrypted” means here.
stored database, mail and queues: the live data volume uses
LUKS2withAES-256-XTS(aes-xts-plain64, a 512-bit combined xts key). most fields below rely on this volume encryption. addresses, subjects and settings are readable to the application after the volume is unlocked.separately encrypted secrets: authenticator secrets and internal webmail passwords use
AES-256-GCM, with a fresh 12-byte nonce, a 16-byte authentication tag and purpose-bound additional data. the key is supplied separately from the database through protected service credentials. staff authenticator secrets use a separate key and purpose.hashed credentials:
Argon2id,SHA-256andHMAC-SHA-256below are verification or lookup methods, not reversible encryption. they serve different jobs; we do not use a fast sha-256 hash as your account-number verifier.backups: restic encrypts backup content and filenames on our server before upload to cloudflare r2, using
AES-256-CTRwithPoly1305-AESauthentication. see the restic format.the limit: the running server and its operator can read ordinary mail and metadata. unlock and recovery keys are server-managed. this is not end-to-end or zero-access encryption, and it does not protect against control of the running server.
we store this about your account.
identity:
id,primary_address,status— a random internal account id, your chosen address and whether setup is pending, the account is active, or deletion is underway. these connect your mailbox and account features.account-number lookup:
credential_lookup,lookup_version— anHMAC-SHA-256lookup of your number and the server-key version used to make it. this finds the account without putting the readable number in the account table.account-number verification:
credential_verifier— a saltedArgon2idverifier. current parameters are 64 mib memory, 3 iterations, parallelism 1 and a 32-byte output. the encoded value includes the salt and parameters. this checks the number you enter; it cannot reveal the original number through a decryption operation.credential history:
credential_version,credential_changed_at,security_revision,revision— version counters and the latest rotation time. these reject stale sessions, security approvals and conflicting changes; they are not a history of your old account numbers.setup times:
created_at,activated_at,pending_until— when the account was created, activated and due to expire if setup was not completed. pending setup lasts 24 hours.plan and storage:
paid_until,anchor_day,committed_bytes— your paid-through date, calendar renewal anchor and recorded storage commitment. these apply your plan and keep capacity accounting consistent.activity and controls:
last_activity,inactivity_months,sending_suspended,deletion_requested_at— recent activity, an optional inactivity-deletion setting, sending restrictions and a deletion request time. successful external mail-app logins update activity at minute precision; wrong passwords and internal webmail authentication do not. inactivity deletion starts disabled.passkey handle:
webauthn_handle— a random 32-byte identifier used by passkeys, separate from your account number and address.
we store this to keep sign-in working.
browser sessions:
id,account_id,token_hash,label,created_at,touched_at,absolute_until,revoked_at— which account a session belongs to, its label and lifetime. the database stores aSHA-256token hash; your browser holds the random bearer cookie. sessions expire after 7 days idle or 30 days total. there is no ip-address or user-agent field in this session record.setup access:
bootstrap_tokens.token_hash,account_id,expires_at— aSHA-256hash of the temporary activation token and a 10-minute deadline. this lets a new account finish setup.authenticator apps:
totp_secret,totp_last_step— your separatelyAES-256-GCMencrypted shared secret and the last accepted time step. the server needs the secret to check codes; the time step prevents replay. the qr code is generated locally.recovery codes:
account_id,code_hash,used_at—SHA-256hashes of random recovery codes and whether each has been used. a code works once and replaces a second factor, not your account number.passkeys:
id,account_id,credential_id,public_key,counter,transports,device_type,backed_up,label,created_at— the public key and identifiers needed to verify a signed response, replay counter, connection hints and single-device or synced-key flags. labels are random. we do not store the private key, fingerprint, face scan, device model, aaguid or identifying attestation. your device or password manager still knows the passkey belongs to vaelmail.com.mail-app credentials:
id,account_id,login,label,verifier,scope,created_at,last_used_at,revoked_at— an independent login, your label, anArgon2idpassword verifier, imap/smtp permissions and usage/revocation times. the generated password is shown once. revoked credential records are eligible for cleanup after 90 days.internal webmail access:
internal_mail_credentials.account_id,credential_id,encrypted_secret— the service’s separate mail credential. unlike a customer app password, this secret must be retrievable, so it is separately encrypted withAES-256-GCM. webmail and the worker use it to access your canonical mailbox.
we store this about your addresses.
addresses and aliases:
id,address,kind,account_id,mailbox_id,state,created_at,metadata— the address, its type, owner, destination mailbox, receiving state and optional description/settings. these route mail and show your alias list.release and retirement:
reserved_until,previous_owner,preferred_free— a released custom alias’s 24-hour reservation, its prior owner while applicable, and your preference for which aliases survive a downgrade. primary and random addresses stay retired rather than being given to someone else.custom domains:
id,account_id,name,proof,state,mx_ready,verified_at,checked_at,proof_lost_at,created_at,metadata— your domain, public dns verification token and validation state/times. the token is meant to appear publicly in dns; it is not a password.domain recipients:
domain_recipients.id,domain_id,address_id— the explicitly allowed recipients for a domain. these connect a verified domain to its receiving addresses.
we store this about your mail.
original messages: bodies, headers, attachments, drafts, folders, flags and native uid/index files live in dovecot’s maildir on the encrypted volume. these are the canonical messages. postgres does not hold a second message-body or attachment-byte column for ordinary mail.
message locations:
mail_projection.id,account_id,folder,uidvalidity,uid,message_id,thread_id,flags,revision,updated_at— pointers, conversation grouping and read/starred state for webmail. this index can be rebuilt from the mailbox.message metadata: inside
mail_projection.metadatawe storesender,subject,createdAt,to,cc,bcc,deliveredTo,references,bytes,attachmentCount,attachmentNames,direction,categories,senderDomainand, when present,draftId. these support the inbox, search, categories, attachment links and routing views.previewis stored as an empty string; it is not a saved body excerpt.codes in messages: extracted
detectedCodevalues are not persisted. they are derived from the canonical message when needed. a code already present in an original subject, body or attachment still exists there, including in stored subject metadata.sync progress:
mailbox_cursors.account_id,folder_identity,uidvalidity,highest_modseq,last_uid— where indexing stopped, so it can continue without rereading every message.attachment pointers:
mail_attachment_refsstoresid,account_id,message_id,part_index;draft_attachment_refsstoresid,account_id,message_id. these authorize access to the correct canonical attachment. the attachment bytes stay in maildir.snooze and undo:
mail_snoozesstores the message, account,previous_folder,due_atandjob_id;mail_undosstoresid,account_id,payload,expires_at,created_at. these restore a move or wake a snoozed message. expired undo records are pruned.temporary uploads: staged attachment mime exists until committed, discarded or expired after 24 hours. it uses encrypted mailbox storage. backup selection excludes temporary upload staging.
we store this to remember your setup.
preferences:
settings.account_id,data,revision— mail preferences such as timezone, appearance, image policy and website icons, plus a counter to prevent conflicting saves.contacts:
contacts.id,account_id,data,revision— the contact details you save, such as names and addresses. these are optional and server-readable on the encrypted volume.organization:
mailbox_metadata.id,account_id,kind,data,revision— folders, labels, filters, services and saved searches, including their names, conditions and actions. compiled sieve scripts are also stored on encrypted mail storage.filter progress:
mail_filter_state.account_id,desired_revision,applied_revision,last_error,updated_at— whether your latest rules reached the mail service and a bounded error code if they did not.dismissed services:
service_dismissals.account_id,domain,created_at— service suggestions you dismissed, so they do not keep returning.sender logos:
sender_icons.domain,bytes,type,checked_at,retry_at— a shared domain-level image cache and retry timing. website icons are on by default and can be switched off. requests go through vael; the remote site receives the domain-logo request, not your account or message id.
we store this when you send mail.
background jobs:
jobs.id,account_id,kind,state,dedupe_key,payload,run_at,leased_until,attempts,last_error,created_at— what work is due, its progress, retry timing and duplicate-prevention identity. payloads hold task-specific pointers and results. send jobs can include recipient outcomes and queue identifiers.frozen outgoing mail: the exact outgoing mime is saved in the reserved
Sendingmailbox, and accepted transport work can also exist in the postfix queue. these bytes use encrypted storage and are needed for delivery and recovery.submission identity:
mail_submissions.job_id,account_id,draft_id,revision,message_id,sender,recipients,uidvalidity,uid,raw_sha256,raw_bytes,created_at— the selected draft, frozen envelope, mailbox pointer, size andSHA-256integrity check. the hash identifies those bytes; it does not encrypt them.delivery and sent-copy results:
accepted_at,rejected_recipients,recipient_result_unknown,sent_copy_at,cleaned_at— what the transport acknowledged and whether the sent copy was saved. an uncertain acknowledgement is held for resolution, never automatically resent. fully cleaned, accepted submission detail is eligible for cleanup after 90 days; unresolved work is retained.sending limits:
mail_send_usage.account_id,bucket,messages,recipients— minute-bucket counts used to enforce sending and recipient limits.account notices:
account_notifications.id,account_id,kind,deadline,created_at,delivered_at— which plan or lifecycle notice is due and whether it was delivered.
we store this about payments.
order and price:
orders.id,account_id,creation_request,months,eur_cents,state,created_at— your purchase request, plan duration, euro price and status. the request id prevents a retried checkout from becoming a second purchase.invoice:
track_id,asset,network,network_name,network_aliases,address,memo,memo_required,quoted_amount,required_confirmations,payable_until— the processor reference and exact payment instructions. a payment address is not a wallet private key.verification and recovery:
provider_hash,received_gross,overpaid_amount,exception_code,capacity_bytes,reconcile_until,reconcile_next_at,reconcile_lease_until,reconcile_lease_token,reconcile_attempts,last_reconciled_at— canonical-result digest, amounts when reliably known, review reason and bounded reconciliation progress. raw provider responses are not retained as invoice records.callbacks:
payment_events.event_hash,order_id,track_id,status,received_at,processed_at— callback digests and processing state, so repeated notifications do not repeat a grant. raw callback bodies are discarded after verification/processing.paid access:
entitlement_grants.id,order_id,account_id,months,paid_until,granted_at,source— the unique paid term or staff grant already applied. this prevents double-crediting.manual review/refund records:
operator_payment_records.id,order_id,operator_id,kind,eur_cents,reference,reason,created_at— staff notes or a record of an external refund. recording one does not transfer funds.retention: settled technical detail is eligible for removal after 90 days; settled gross/excess and financial reason detail after 24 calendar months. minimal order, payment, grant and refund replay identities remain. open reviews and late-payment proof have exceptions. deleting an account detaches financial account links rather than erasing all payment records. oxapay and public blockchains have their own visibility and retention.
we store this if you contact support.
browser identity:
support.visitors.id,number,session_hash,created_at,expires_at— a random 12-digit visitor label and aSHA-256hash of a separate random cookie. it lasts 180 days and does not grant account or mailbox access. there is no account-id link in this visitor record.ticket:
support.tickets.id,visitor_id,subject,chat_id,display_name,channel_id,state,created_at,closed_at— your subject, conversation identity, bridge destination and open/closed state. telegram support additionally uses the platform’s chat identity.conversation:
support.web_messages.id,ticket_id,sender,body,request_id,created_atandsupport.web_files.id,message_id,name,bytes— the conversation, replay protection and stored reply attachments. browser conversations are mirrored to private discord ticket channels. closing a ticket does not delete it; content stays until staff deletion. the newest 100 messages shown in the panel are not the full retention limit.bridge progress:
support.jobsandsupport.messagesretain ticket/event ids, queued delivery payloads, progress, retry times, safe error codes and platform message ids. these deliver replies and prevent accidental duplicates.support limits:
support.rate_windows.key,hits,reset_at— visitor/platform counters and, for browser-source limits, a deterministicSHA-256digest derived from the connection address. this is separate from the rotating login limiter; a digest is not encryption or guaranteed anonymity. stale windows are cleaned after their reset time is over an hour old.
temporary data, your browser and other providers.
authentication cache: local volatile redis holds short-lived challenges, pending logins, security/image approvals, verification leases and
HMAC-SHA-256pseudonymous abuse counters. most expire within 10 minutes; passkey/login challenges within 5 minutes. some setup records contain secrets or security material. redis has no disk persistence and is excluded from backups.scanning cache: local antivirus checksum/results can remain in volatile redis for an hour. mail is scanned locally; signature updates and dns-based spam/reputation checks contact external services.
your browser: session cookies keep you signed in.
vael-privacy-modein local storage remembers the visual blur switch; it does not encrypt or remove page content. optional local draft recovery stores draft data in indexeddb on your device. downloaded mail, exports and recovery codes follow your device’s storage lifecycle.remote images: approved message images are fetched by vael, using temporary version-bound approvals. the remote host can still learn that its particular image url was requested. message-body images are blocked by default; domain logos are a separate setting.
website traffic: cloudflare terminates website https and processes requests/responses, including submitted account and support data. this is separate from r2’s encrypted backups. hosting, dns, payment and mail providers also process the data needed for their part of the service. tls between mail servers depends on the other provider’s support.
operations, backups and deletion.
staff actions: separate operator records hold password verifiers, encrypted authenticator secrets and hashed sessions.
operator_auditholdsid,operator_id,action,target,request_id,command_hash,details,created_at. these show who changed what and stop a repeated request from repeating an action. detail expires after 180 days; minimal action/request identities remain.health records: bounded service, queue, storage, scanner and backup counts/statuses support operations. metric archives cover 30 utc dates; event archives cover 14. these are aggregate records, not saved mailbox bodies or browser session replay. vael website access logs are disabled; this does not promise that infrastructure providers keep no logs.
mail-health reports:
mail_reports.digest,kind,domain,successful,failed,received_at— deduplication and aggregate authentication/tls counts. raw report mail is retained up to 7 days; aggregates up to 90 days.recovery copies: encrypted-volume postgres recovery state includes database pages and transaction logs. daily encrypted offsite backups include database records, canonical mail/uid state, queued mail, deletion history and protected service configuration/recovery keys. the restic password and r2 credentials are excluded from those snapshots. old database pages and transaction logs can contain earlier values.
backup retention: routine snapshots roll over after 7 days, but the newest verified consistent snapshot is kept if newer backups fail, so it can be older. forgotten data can remain in shared backup packs until pruning/repacking. deleting a live record is not immediate secure erasure of every historical copy.
deletion safety:
deletion_ledger.account_id,requested_at,purged_at, plus a durable deletion journal containing account id, immutable primary address, request/record times and a checksum. these stop a restore from reviving a deleted account. primary/random address retirement and necessary replay records remain; the live mailbox and account-owned records are purged.
what we do not ask you for.
no real name, home address, phone number, date of birth, identity document, identity selfie or recovery email to register.
no advertising analytics, browser fingerprinting or session replay. ordinary account/session tables do not have client-ip or user-agent columns; the support rate digest, provider processing and original mail headers described above are separate.
no readable account number in the normal account database, no customer app-password plaintext verifier, and no passkey private key. credentials still pass through memory when entered or issued. personal information you put in mail, contacts, support or free-text labels becomes part of that content.
read the privacy policy, follow your data through the system, or manage exports and deletion on your data page.