your-mail-mcp
Acesso MCP somente leitura e auto-hospedado a e-mails IMAP, espelhado em um maildir local e indexado por notmuch.
Documentação
your-mail-mcp
Seu e-mail já contém as respostas: referências de reserva, códigos de portão, faturas, períodos de garantia, promessas que as pessoas fizeram por escrito. Este servidor permite que seu assistente de IA as encontre.
Pergunte coisas como:
- "Encontre a referência de reserva da balsa de junho."
- "Qual era a senha do Wi-Fi que o hotel enviou no verão passado?"
- "O que o contador respondeu sobre o IVA, e quando?"
- "Reúna tudo entre mim e o construtor sobre o telhado, em ordem, e resuma quem prometeu o quê."
- "O que chegou esta manhã, em todas as minhas contas, que realmente precisa de mim?"
Use para:
- Busca que entende perguntas. Busca de texto completo em todo o seu histórico, todas as contas em um único índice, formulada do jeito que você pensa, em vez do jeito que a sintaxe de busca funciona.
- Triagem pelo celular. Um resumo matinal do que chegou durante a noite, com o lixo já filtrado, de onde quer que você esteja.
- E-mail como contexto para outros trabalhos. Extraia os requisitos do cliente da conversa e leve-os para sua sessão de codificação ou escrita, em vez de redigitá-los.
- Agentes que você pode deixar rodando. O servidor só pode ler. Um e-mail malicioso que chega ao seu assistente é lido e nada mais, porque enviar, excluir e mover não existem aqui. Isso torna resumos agendados e agentes sempre ativos algo tranquilo de executar.
A configuração são dois arquivos e docker compose up -d — veja Executando.
Um servidor MCP auto-hospedado que dá a um cliente MCP (Claude, ou qualquer outro cliente que fale HTTP MCP com streamable e OAuth) acesso de leitura ao seu e-mail. Ele espelha uma ou mais contas IMAP em um maildir local com mbsync, indexa-os com notmuch e responde a chamadas de ferramentas a partir desse índice.

O e-mail só se move da esquerda para a direita nesse diagrama. A única seta
que o servidor faz de volta para um provedor é uma única LIST IMAP na
inicialização, para descobrir como esse servidor chama suas pastas de lixo e
spam; ele nunca seleciona uma caixa de correio e nunca busca uma mensagem. A
fonte do diagrama é
docs/diagrams/how-it-works.html.
O que ele não pode fazer
A propriedade somente leitura está embutida na arquitetura.
O espelho é somente de pull. A configuração mbsync gerada para cada conta
carrega Sync Pull, Create Near, Remove None, Expunge None — nada nessa
configuração pode enviar uma alteração de volta ao servidor, excluir uma
mensagem ou expurgar uma.
A única operação IMAP em qualquer lugar do código Go é LIST, emitida uma
vez por conta na inicialização para encontrar as pastas de lixo e spam de cada
conta (veja Notas do provedor e
Solução de problemas).
Essa conexão faz login, lista caixas de correio e faz logout. Ela nunca
seleciona uma caixa de correio e nunca busca uma mensagem.
Não há envio, exclusão, movimentação ou marcação. Os anexos são listados em
show e thread e servidos somente leitura pela ferramenta
attachment, uma parte por vez, com limite de 5MB. Partes maiores são servidas
cruas em GET /attachment/{id}/{part}, autenticadas por um token bearer ou pelo
link assinado de curta duração que a ferramenta retorna quando recusa uma parte
superdimensionada. Nada no processo tem acesso de escrita a qualquer conta.
Onze ferramentas, todas somente leitura:
| Ferramenta | O que faz |
|---|---|
search | Busca e-mail. Retorna resumos de conversas como JSON. |
ids | Retorna os IDs de mensagem que correspondem a uma consulta. |
files | Retorna os caminhos de arquivo maildir que correspondem a uma consulta. |
count | Conta as mensagens que correspondem a uma consulta. |
show | Mostra uma mensagem: cabeçalhos e corpo decodificado, como JSON. |
thread | Mostra a conversa inteira que contém uma mensagem. Exclui respostas de lixo/spam por padrão; defina include_excluded para incluí-las. |
text | Retorna o corpo em texto simples de uma mensagem, convertendo HTML. |
folders | Lista contas, suas pastas, tags de índice e a última sincronização e último erro de cada conta. |
refresh | Sincroniza a caixa de entrada agora e relata quantas mensagens chegaram. |
status | Saúde da sincronização por conta: conclusão da primeira sincronização, última sincronização, mensagens indexadas, erros e backoff. |
attachment | Um anexo ou parte MIME de uma mensagem, pelo número da parte de show. Imagens e binários como conteúdo tipado, texto como bloco marcado. Partes acima de 5MB recebem um link de download assinado. |
search, ids, files e count aceitam uma consulta
notmuch (from:, to:,
subject:, tag:, folder:, date:2026-01-01..2026-06-30, combinadas com
e/ou/não), um account opcional para limitar a uma conta, e podem incluir
lixo/spam com include_excluded.
Executando
Três maneiras de executar isso. Elas diferem em uma coisa: quem pode acessar o servidor. Comece no caso 1 e suba apenas quando precisar. Nenhum deles é endurecido além dos padrões — isso é Endurecimento, mais abaixo, e é deliberadamente separado para que você possa fazer funcionar primeiro.
| Onde roda | Quem pode acessar | Seu e-mail é armazenado em | |
|---|---|---|---|
| 1 | sua máquina | apenas essa máquina | sua máquina |
| 2 | sua máquina | você, de qualquer lugar | sua máquina |
| 3 | um VPS | você, de qualquer lugar | um disco alugado |
O servidor é distribuído como imagem de contêiner em
ghcr.io/wildsurfer/your-mail-mcp, construída e publicada por CI para amd64 e
arm64. Nada precisa ser compilado, e todos os casos começam da mesma forma —
dois arquivos em um diretório vazio:
mkdir your-mail && cd your-mail
curl -fsSLO https://raw.githubusercontent.com/wildsurfer/your-mail-mcp/main/compose.yaml
curl -fsSL https://raw.githubusercontent.com/wildsurfer/your-mail-mcp/main/accounts.example.json -o accounts.json
Edite accounts.json com suas contas (veja
O arquivo de contas), depois coloque os segredos que ele
referencia em um arquivo .env ao lado de compose.yaml:
# .env
OAUTH_PASSPHRASE=pick-a-long-one-you-can-type-on-a-smartphone
WORK_PASS=your-gmail-app-password
PERSONAL_PASS=your-icloud-app-specific-password
OAUTH_PASSPHRASE é a única credencial entre a internet e seu e-mail
nos casos 2 e 3. Trate-a de acordo.
Esses dois arquivos contêm as senhas do seu e-mail. Se você colocar este diretório sob controle de versão ou em um backup que saia da máquina, trate-os de acordo.
Caso 1 — na sua máquina, apenas para sua máquina
O servidor vincula ao loopback. Nada fora da sua máquina pode acessá-lo, então não há TLS para configurar nem hostname para possuir. Suas ferramentas de CLI podem usá-lo. Seu smartphone não pode.
Adicione uma linha ao .env:
PUBLIC_URL=http://127.0.0.1:8080
Depois inicie:
docker compose up -d
docker compose logs -f # watch the first sync
A primeira sincronização popula o maildir e leva um tempo em uma caixa de correio grande. É mais lenta do que poderia ser de propósito, um comando IMAP por vez, porque os provedores limitam. Não há etapa separada de inicialização.
Claude Code
claude mcp add --transport http your-mail http://127.0.0.1:8080/mcp
Depois execute /mcp dentro do Claude Code, escolha your-mail e
autentique. Um navegador abre a página de consentimento, que pede uma coisa:
seu OAUTH_PASSPHRASE. Até você fazer isso, claude mcp list mostra
Needs authentication.
Codex
codex mcp add your-mail --url http://127.0.0.1:8080/mcp
codex mcp login your-mail
codex mcp list mostra o status de autenticação. Se as ferramentas ainda não
aparecerem em uma sessão após um login bem-sucedido, isso é um bug conhecido do
Codex em que as credenciais OAuth são obtidas e nunca usadas
(openai/codex#20009). Use a
ponte abaixo até que seja corrigido.
Fallback para qualquer cliente cujo suporte a OAuth esteja quebrado
mcp-remote faz o fluxo OAuth sozinho e reexpõe o servidor via
stdio, que todo cliente MCP suporta:
# ~/.codex/config.toml
[mcp_servers.your-mail]
command = "npx"
args = ["-y", "mcp-remote", "http://127.0.0.1:8080/mcp"]
Ele abre a mesma página de consentimento na primeira execução e armazena os tokens em cache.
Caso 2 — na sua máquina, acessível de qualquer lugar
Mesmo servidor, mais algo que lhe dê um endereço HTTPS público. Seu e-mail permanece na sua máquina, e nada escuta na sua rede doméstica, porque o túnel faz a conexão de saída. Você precisa disso para os aplicativos de smartphone e desktop: um conector personalizado é buscado pelos servidores do fornecedor, então ele não pode acessar um endereço privado.
Com Tailscale (sem necessidade de domínio)
Um comando, igual no macOS e no Linux, e você obtém um hostname HTTPS sem possuir um domínio.
tailscale funnel --bg 8080
--bg mantém isso rodando entre reinicializações. Ele imprime a URL
pública, que parece com https://your-machine.your-tailnet.ts.net. Esse é o hostname a usar:
# .env
PUBLIC_URL=https://your-machine.your-tailnet.ts.net
docker compose up -d
O Funnel precisa de certificados HTTPS e do atributo de nó Funnel habilitado
para sua tailnet; a CLI oferece adicionar a linha de política na primeira vez,
e o resto está no seu console de administração. tailscale funnel status mostra o que
está exposto, e tailscale funnel --https=443 off derruba.
Com Cloudflare (você possui um domínio, e ele está no Cloudflare)
Use isso se quiser um hostname no seu próprio domínio em vez de um
.ts.net. mail.example.com abaixo é seu domínio, já adicionado à
sua conta Cloudflare — o Cloudflare não fornece um hostname para um túnel
nomeado.
cloudflared tunnel login
cloudflared tunnel create your-mail
create imprime o UUID do túnel e o arquivo de credenciais que acabou
de escrever:
Tunnel credentials written to /Users/you/.cloudflared/f9e2…-… .json
Created tunnel your-mail with id f9e2…-…
Use esse caminho exato abaixo; cloudflared tunnel list imprime o UUID novamente se
você o perder. Roteie o hostname, depois escreva ~/.cloudflared/config.yml:
cloudflared tunnel route dns your-mail mail.example.com
tunnel: your-mail
credentials-file: /Users/you/.cloudflared/f9e2….json # the path create printed
url: http://localhost:8080
cloudflared tunnel run your-mail
Para manter rodando: no Linux, sudo cloudflared service install. No macOS,
instale via Homebrew e use brew services start cloudflared, porque o
caminho de instalação do sudo procura seu certificado no diretório
home do usuário root e não encontrará o que cloudflared tunnel login escreveu no seu.
Depois defina PUBLIC_URL=https://mail.example.com em .env e
docker compose up -d.
De qualquer forma
PUBLIC_URL precisa corresponder exatamente ao que você digita no cliente.
O servidor publica PUBLIC_URL + /mcp como o resource em seus metadados
OAuth, e uma incompatibilidade aí é o motivo mais comum para um conector
recusar a adição.
Uma coisa para saber antes de começar no smartphone: nem o Claude nem o ChatGPT permitem adicionar um conector pelo aplicativo do smartphone. Você o adiciona uma vez na web (ou no aplicativo desktop do Claude), e ele então aparece no seu smartphone. Tentar fazer a configuração no próprio smartphone vai desperdiçar seu tempo.
Claude — adicione na web ou no desktop, depois use no seu smartphone
- Em claude.ai ou no Claude Desktop, vá em Configurações → Conectores e clique em + ao lado de Conectores, ou Adicionar conector personalizado.
- Dê um nome e a URL
<PUBLIC_URL>/mcp. Deixe os campos avançados de OAuth vazios: este servidor registra clientes dinamicamente. - O Claude abre a página de consentimento. Insira seu
OAUTH_PASSPHRASE. - Abra o aplicativo Claude no seu smartphone. O conector já está lá, e as ferramentas estão disponíveis em um chat. Ative-o para uma conversa pelo menu de ferramentas ou conectores no compositor.
ChatGPT — adicione na web, depois use no seu smartphone
Conectores MCP personalizados ficam atrás do modo de desenvolvedor, que exige uma conta Pro, Plus, Business, Enterprise ou Education e está disponível apenas na web.
- No ChatGPT na web, abra Configurações → Segurança e login e ative o Modo de desenvolvedor. Em espaços de trabalho Business e Enterprise, um administrador pode precisar permitir primeiro.
- Adicione um conector para um servidor MCP remoto e dê a URL
<PUBLIC_URL>/mcp, com OAuth como autenticação. O ChatGPT suporta registro dinâmico de clientes, então não há nada para colar. - Aprove a página de consentimento com seu
OAUTH_PASSPHRASE. - Abra o ChatGPT no seu smartphone e ative o conector em um chat.
Esses menus mudam. Se os nomes acima não corresponderem ao que você vê, procure pelo modo de desenvolvedor nas configurações e depois pelo lugar que adiciona um conector por URL.
O ChatGPT desativa algumas ações de escrita do MCP no celular. Isso não tem efeito aqui, porque este servidor não tem nenhuma ação de escrita.
Claude Code
claude mcp add --transport http your-mail https://your-host/mcp
Codex
codex mcp add your-mail --url https://your-host/mcp
codex mcp login your-mail
Caso 3 — em um VPS, acessível de qualquer lugar
Escolha isso quando quiser que o espelho permaneça ativo independentemente de sua máquina estar ligada. Custa alguns dólares por mês e uma troca real: uma cópia completa em texto simples do seu e-mail vai para um disco alugado, com as senhas de aplicativo no mesmo ambiente. Leia Segurança antes de escolher. A instalação é o caso 1 mais um túnel, no computador de outra pessoa. Sem portas para abrir, sem DNS para configurar, sem certificados para gerenciar.
Em uma máquina nova com Debian ou Ubuntu:
# 1. Docker
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER && newgrp docker
# 2. The two files, and your accounts
mkdir your-mail && cd your-mail
curl -fsSLO https://raw.githubusercontent.com/wildsurfer/your-mail-mcp/main/compose.yaml
curl -fsSL https://raw.githubusercontent.com/wildsurfer/your-mail-mcp/main/accounts.example.json -o accounts.json
$EDITOR accounts.json # your accounts
$EDITOR .env # OAUTH_PASSPHRASE and the account passwords
# 3. A public address, exactly as in case 2
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale funnel --bg 8080 # prints your https://….ts.net hostname
# 4. Put that hostname in .env, then start
echo "PUBLIC_URL=https://your-machine.your-tailnet.ts.net" >> .env
docker compose up -d
docker compose logs -f
PUBLIC_URL vem por último porque você não sabe o hostname até o passo 3
imprimi-lo.
Conectar um cliente é idêntico ao caso 2.
restart: unless-stopped no compose.yaml traz os contêineres de volta após uma
reinicialização. Verifique com a ferramenta folders, que relata a última
sincronização de cada conta e seu último erro, ou com docker compose logs --tail=50.
Agora vá ler Hardening. Um VPS no qual você consegue entrar via SSH com senha, contendo uma cópia do seu e-mail, é pior do que não executar isso de forma alguma.
Hardening
Nada disso é necessário para fazer o servidor funcionar, por isso não está nos passos de instalação. Está ordenado pelo quanto ele te beneficia. O caso 1 não precisa de nada disso.
Escolha uma frase-senha de verdade. OAUTH_PASSPHRASE é a porta inteira. Um chute
errado custa ao atacante um segundo, e os chutes são serializados, então executá-los
em paralelo não ajuda, mas nenhuma dessas coisas salva uma frase-senha curta.
Use uma longa que você ainda consiga digitar em um smartphone.
Bloqueie o SSH (caso 3). Uma máquina alugada com login por senha e uma cópia do seu e-mail é a pior combinação neste documento. Como root, antes de qualquer outra coisa:
adduser mail && usermod -aG sudo mail
rsync --archive --chown=mail:mail ~/.ssh /home/mail
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/; s/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh
Depois faça a instalação como mail, não como root.
Feche as portas que você não está usando (caso 3). Com um túnel, você não precisa de nenhuma porta de entrada, então:
sudo ufw allow OpenSSH && sudo ufw --force enable
Restrinja quem pode alcançar o conector. Se a única coisa que fala com o seu
servidor é um conector personalizado em um app Claude, esse tráfego chega a partir
da faixa de saída publicada da Anthropic, 160.79.104.0/21, e você pode recusar
todo o resto no túnel ou no firewall. Não faça isso se você também usa
Claude Code ou Codex de um laptop, pois eles se conectam de onde você estiver.
Faça backup dos volumes ou aceite uma ressincronização. compose.yaml mantém o maildir
e o índice em volumes nomeados. Nada neles é único — tudo ainda está no seu
servidor de e-mail — mas baixar novamente uma caixa de entrada grande leva um tempo
e incomoda provedores que limitam a largura de banda.
Saiba o que a frase-senha não protege. Ela protege a superfície MCP. Ela não criptografa nada em repouso. Veja Security.
Seu próprio domínio e certificado em vez de um túnel
Se você preferir encerrar o TLS você mesmo em um domínio que possui, aponte um registro A
para a máquina e coloque o Caddy na frente. Adicione compose.override.yaml:
services:
caddy:
image: caddy:2
restart: unless-stopped
ports: ["80:80", "443:443"]
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
volumes:
caddy_data:
# Caddyfile
mail.example.com {
reverse_proxy your-mail-mcp:8080
}
Abra ambas as portas — a 80 não é opcional, o Caddy a usa para o desafio de certificado e o redirecionamento HTTPS:
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
O Caddy obtém e renova o certificado sozinho. Defina PUBLIC_URL para o
hostname e docker compose up -d.
O arquivo de contas
Montado somente leitura em /config/accounts.json (veja compose.yaml). JSON,
analisado com encoding/json, expandido contra o ambiente do processo antes da
análise, então ${VAR} em qualquer valor de string é substituído pela variável
de ambiente com esse nome. É assim que os segredos ficam fora do arquivo:
{
"accounts": [
{
"name": "work",
"host": "imap.gmail.com",
"user": "you@example.com",
"password": "${WORK_PASS}"
}
]
}
Chaves por conta:
| Chave | Padrão | Observações |
|---|---|---|
name | — | Obrigatório. Sem espaços, aspas ou barras (normais ou invertidas). Torna-se o diretório maildir de nível superior para a conta e o argumento account nas chamadas de ferramenta. |
host | — | Obrigatório. Hostname do servidor IMAP. |
port | 993 (imaps) ou 143 (caso contrário) | |
user | — | Obrigatório. Veja Provider notes: o iCloud quer o nome curto, não o endereço de e-mail completo. |
password | — | Obrigatório. ${VAR} é expandido a partir do ambiente; uma senha literal também funciona, mas não é recomendada. |
tls | imaps | imaps, starttls ou none. |
patterns | ["*"] | Padrões de pastas do mbsync — quais pastas espelhar. |
exclude_folders | descoberto automaticamente | Nomes de pastas a excluir da busca por padrão (veja SPECIAL-USE discovery). Definir isso substitui completamente a descoberta para aquela conta. |
Um nome de conta deve ser único. Pelo menos uma conta é obrigatória; um
array accounts vazio é um erro de inicialização.
Variáveis de ambiente
| Variável | Obrigatória | Padrão | Significado |
|---|---|---|---|
CONFIG | sim | — | Caminho para o arquivo de contas. |
MAILDIR | sim | — | Raiz do maildir; cada conta recebe um subdiretório. |
INDEX | sim | — | Diretório do índice notmuch/Xapian. |
PUBLIC_URL | sim | — | A URL externa pela qual o servidor é acessado, exatamente como um cliente a usará (uma barra final, se houver, é removida). Usada nos metadados OAuth e deve corresponder ao que você digita no cliente. |
OAUTH_PASSPHRASE | sim | — | A única frase-senha que protege a tela de consentimento. |
SYNC_INTERVAL | não | 10m | Período de sincronização completa, como uma duração Go (5m, 1h). O padrão segue a cadência recomendada de clientes IMAP do Google, de 10 minutos. Uma conta que falha repetidamente é tentada novamente no dobro desse intervalo, depois no quádruplo, com limite de uma hora, para que uma queda do provedor ou bloqueio de cota não seja martelado. |
SYNC_TIMEOUT | não | 1h | Prazo por conta para uma execução do mbsync, como uma duração Go. Uma execução interrompida pelo prazo retoma de onde parou na próxima passada, então um primeiro espelhamento grande é concluído em partes. Pense antes de aumentar isso em uma configuração com várias contas: as contas sincronizam uma de cada vez, então uma conta travada em uma conexão limitada bloqueia as outras durante todo o prazo. |
LISTEN_ADDR | não | :8080 | Endereço ao qual o servidor HTTP faz bind. |
INIT_MIRROR | não | não definido | Defina como 1 para sincronizar em um diretório vazio que não é um ponto de montagem. Não é necessário com o compose, onde /mail é um volume. |
CONFIG, MAILDIR e INDEX são obrigatórias; o processo se recusa a iniciar
sem elas. PUBLIC_URL e OAUTH_PASSPHRASE são obrigatórias pela camada
OAuth e o processo também falha ao iniciar sem elas.
A imagem do contêiner já define quatro delas (Dockerfile):
MAILDIR=/mail, INDEX=/index, CONFIG=/config/accounts.json,
LISTEN_ADDR=:8080. compose.yaml não substitui nenhuma delas. Deixe-as
em paz, a menos que você também esteja alterando a montagem de volume ou de configuração correspondente
em compose.yaml — uma substituição que não move a montagem junto aponta
o servidor para um caminho vazio ou inexistente.
Sem Docker
Binários de lançamento para Linux e macOS, amd64 e arm64, estão na
página de lançamentos, com
checksums. O binário chama mbsync, notmuch e w3m, então instale
esses primeiro — brew install isync notmuch w3m no macOS,
apt install isync notmuch w3m no Debian e Ubuntu. isync 1.4.4 ou mais novo
funciona.
Depois, a mesma configuração do contêiner, com caminhos de sua escolha.
Os volumes do contêiner começam como pontos de montagem, que a proteção de maildir vazio
lê como uma primeira execução genuína; um diretório comum que você cria
parece exatamente um volume ausente para essa mesma proteção, então ela precisa
de INIT_MIRROR=1 para dizer que realmente é uma primeira execução aqui:
mkdir -p mail index
CONFIG=./accounts.json MAILDIR=./mail INDEX=./index INIT_MIRROR=1 \
PUBLIC_URL=http://127.0.0.1:8080 OAUTH_PASSPHRASE=... \
WORK_PASS=... ./your-mail-mcp
O Windows não é suportado: o tratamento do maildir depende de semânticas de sistema de arquivos Unix, e não há mbsync para chamar.
Compilando você mesmo
O CI compila, testa e publica cada imagem, então ninguém precisa — mas é um
comando se você quiser: docker build -t your-mail-mcp . para o contêiner,
ou go build para o binário (Go 1.27, com as três ferramentas acima no PATH para
os testes).
Notas do provedor
As notas do iCloud vêm da operação de longo prazo de um espelho iCloud real que antecede este servidor. As notas do Gmail e do Dovecot vêm da documentação do provedor e da pesquisa do projeto, e nem todas foram reverificadas através deste servidor ainda.
- iCloud (
imap.mail.me.com): ouserIMAP é o nome curto — a parte antes de@icloud.com— não o endereço de e-mail completo. O iCloud limita conexões IMAP simultâneas; é por isso que a configuração mbsync gerada fixaPipelineDepth 1para cada conta, e isso não é configurável. - Gmail (
imap.gmail.com): exige uma Senha de App, que exige verificação em duas etapas habilitada na conta primeiro — o Gmail não aceita a senha da conta diretamente via IMAP. O Gmail também mantém uma cópia de praticamente tudo em[Gmail]/All Mail, então o espelho de uma conta Gmail tem aproximadamente o dobro do tamanho que a lista de pastas sugere, já que a maioria das mensagens existe tanto na pasta delas quanto em All Mail. O primeiro espelhamento de uma conta Gmail grande leva horas, e o Google também impõe uma cota diária de download IMAP (cerca de 2,5 GB por dia), então uma caixa de entrada com vários gigabytes distribui o primeiro espelhamento por vários dias. Isso é normal: o servidor continua tentando em seu cronograma e o mbsync retoma de onde parou. DefinaSYNC_TIMEOUTpara algo como8hpara o primeiro espelhamento para que uma execução longa não seja interrompida pelo prazo padrão de uma hora. - Servidores Dovecot (muitos provedores auto-hospedados e menores) comumente
prefixam nomes de pastas com
INBOX.(ex.:INBOX.Sent). Sefoldersmostrar nomes de pastas que você não esperava, geralmente é por isso.
Segurança
As senhas das contas são fornecidas através do ambiente do processo (${VAR} em
accounts.json, ou valores literais). Na inicialização, o servidor as escreve em
um arquivo de configuração mbsync gerado no disco dentro do contêiner, com modo de arquivo
0600. Esse arquivo não é criptografado. Qualquer coisa que possa ler o
ambiente do contêiner, ou esse arquivo, pode ler as senhas em texto
puro.
Proteção em repouso — criptografia de disco, restringir quem pode executar comandos no contêiner, acesso ao host — é responsabilidade do operador. Este servidor não afirma criptografar credenciais em repouso e não tenta fazê-lo.
A frase-senha OAuth é verificada em tempo constante e protege todo o servidor
com um único segredo compartilhado; não é um sistema de credenciais por usuário. Trate
OAUTH_PASSPHRASE e as senhas das contas de e-mail com o mesmo cuidado.
Os resumos de tópicos do search incluem um nome de exibição para cada mensagem em um
tópico correspondente, que um remetente controla. Uma mensagem em uma pasta excluída por
padrão (lixo, lixeira) ainda pode colocar seu próprio nome escolhido pelo atacante na sua frente
dessa forma, mesmo que o corpo dela nunca apareça — search não busca nem
mostra o corpo de uma mensagem excluída. thread e show são caminhos de leitura, não
sujeitos a isso: thread exclui respostas de lixo/lixeira por padrão (veja
a tabela de ferramentas acima), e show lê uma única mensagem para a qual você já tem o
id. Esse vazamento de nome de exibição no search não é corrigido nesta versão.
Solução de problemas
"maildir ... is an empty plain directory, not a mount point: refusing to
sync" — o servidor verifica se o seu maildir é um sistema de arquivos montado. Um
volume montado que por acaso está vazio é uma primeira execução e sincroniza sem
opt-in, por isso o compose não precisa de passo extra. Um diretório vazio comum
é ambíguo: um maildir novo parece exatamente um caminho cujo volume nunca foi
montado, e sincronizar no segundo rebaixa todas as contas
para um diretório que desaparece no momento em que você corrige a montagem. Monte
o armazenamento onde MAILDIR aponta, ou defina INIT_MIRROR=1 se realmente
for para ser um diretório comum neste sistema de arquivos.
"maildir ...: no such file or directory" — o caminho não existe de
forma alguma. Com o compose, isso significa que o volume ou bind mount está faltando em
compose.yaml; executando o binário diretamente, significa que MAILDIR está errado.
Verifique o status de sincronização por conta com a ferramenta folders. Ela lista cada
conta configurada, o horário da última sincronização bem-sucedida, o último erro, se houver,
suas pastas e as tags no índice. Uma única conta com senha incorreta
ou senha específica de aplicativo expirada não impede as outras —
falhas de sincronização são isoladas por conta — mas ela aparecerá aqui como uma
linha last error, não como silêncio.
Exclusão de lixo eletrônico/lixeira, dois formatos diferentes de falha:
- "special-use discovery: account NOME: ..." nos logs do contêiner
significa que a conexão inicial, o login ou o
LISTpara essa conta falhou completamente. Nessa falha, não há nomes de pastas para recorrer à correspondência, então essa conta fica sem nenhuma exclusão — nem mesmo pela lista de nomes em inglês embutida — até que o problema de conexão seja corrigido ouexclude_foldersseja definido manualmente para ela. - Nenhuma linha de erro, mas
foldersainda mostra nada excluído significa que oLISTfoi bem-sucedido — o servidor simplesmente não anuncia atributos\Junk/\Trash(sem suporte a SPECIAL-USE RFC 6154) e os nomes das pastas não correspondem à lista em inglês embutida (junk,spam,trash,deleted messages,deleted items,bulk mail). Este é o caso de caixa de correio localizada — uma caixa de correio alemã ou francesa, por exemplo — e a correção é a mesma: definaexclude_foldersmanualmente.
exclude_folders em accounts.json, por exemplo, "exclude_folders": ["Papierkorb"], tem prioridade sobre SPECIAL-USE e a lista embutida
em todos os casos.