Email Agent MCP
Conectividade de e-mail local para agentes de IA — ler, rascunhar, enviar e organizar e-mails do Outlook via MCP. Licenciado sob Apache-2.0.
Documentação
Agent Email
English | Español | 简体中文 | Português (Brasil) | Deutsch
email-agent-mcp por UseJunior -- conectividade de e-mail local para agentes de IA.
Agent Email é um servidor MCP TypeScript de código aberto que permite ao Claude Code, Cursor, Gemini CLI, OpenClaw e outros runtimes compatíveis com MCP ler e-mails, pesquisar conversas, redigir respostas, rotular mensagens, alterar estado de leitura, mover mensagens e enviar correspondência pela sua própria caixa de entrada. Microsoft 365 / Outlook e Gmail são suportados hoje. Padrões com foco em segurança significam que agentes não podem enviar e-mails até que você configure explicitamente uma lista de permissões.
Início Rápido
npx -y email-agent-mcp
O assistente de configuração interativo guia você pela configuração OAuth e seleção da caixa de entrada.
O Que Funciona Hoje
- Acesso à caixa de entrada do Microsoft 365 / Outlook via MCP stdio
list_emails,read_email,search_emailseget_threadcreate_draft,update_draft,send_draft,send_emailereply_to_emaillabel_email,mark_reademove_to_folder- listas de permissões de envio, exclusão desabilitada por padrão e erros sanitizados
A passagem atual de preparação para lançamento foi validada contra uma caixa de entrada real do Outlook para fluxos de leitura, rascunho, envio, categorização, movimentação e estado de leitura.
Por Que Isso Existe
Agentes de IA precisam ler, responder e agir sobre e-mails, mas as APIs de e-mail são complexas. Fluxos OAuth, consultas delta do Graph, assinaturas push do Gmail, conversão de HTML para markdown, semântica de conversas -- cada provedor tem suas peculiaridades.
Agent Email encapsula essa complexidade em ferramentas MCP determinísticas com proteções de segurança:
- listas de permissões de envio e recebimento que controlam com quem os agentes podem contatar
- exclusão desabilitada por padrão (exige aceitação explícita)
- sanitização de erros que remove chaves de API, caminhos de arquivo e rastreamentos de pilha
- sandboxing de arquivos de corpo com proteção contra travessia de caminho
Uso com Claude Code
Adicione ao ~/.claude/settings.json ou ao .claude/settings.json do seu projeto:
{
"mcpServers": {
"email-agent-mcp": {
"type": "stdio",
"command": "npx",
"args": ["-y", "email-agent-mcp"]
}
}
}
Uso com Cursor
// .cursor/mcp.json
{
"mcpServers": {
"email-agent-mcp": {
"command": "npx",
"args": ["-y", "email-agent-mcp"]
}
}
}
Uso com Gemini CLI
gemini extensions install https://github.com/UseJunior/email-agent-mcp
Uso com OpenClaw
Adicione um bloco mcp ao ~/.openclaw/openclaw.json:
{
// ... existing config ...
mcp: {
servers: {
email: {
command: "npx",
args: ["tsx", "/path/to/email-agent-mcp/packages/email-mcp/src/serve-entry.ts"],
transport: "stdio"
}
}
}
}
Nota de versão: A chave de configuração
mcpexige OpenClaw app >= 2026.3.24. Se o CLI for mais antigo que o app, ele pode rejeitar essa chave durante a validação, mesmo que o gateway a aceite. Atualize o CLI comnpm install openclaw@latestno seu diretório NemoClaw, ou reinicie o gateway diretamente comlaunchctl kickstart -k gui/501/ai.openclaw.gateway.
Observador de e-mail
O observador consulta sua caixa de entrada e envia sinais de ativação ao OpenClaw quando novos e-mails chegam:
# Set the hooks token (must match hooks.token in openclaw.json)
export OPENCLAW_HOOKS_TOKEN="your-hooks-token"
# Start the watcher (defaults to http://localhost:18789/hooks/wake)
npm run dev:watch
O observador exige pelo menos uma caixa de entrada configurada. Execute npx email-agent-mcp ou npm run dev:configure primeiro para concluir o fluxo OAuth.
Teste Rápido de Preparação para Lançamento
Antes de gravar uma demonstração, execute o script de teste rápido ao vivo contra uma caixa de entrada real e uma lista de permissões de envio segura. O script exercita:
get_mailbox_statuslist_emails+read_emailmark_readnão lido -> lido -> não lidolabel_emailem um candidato seguro da caixa de entradacreate_draftreply_to_emailapenas rascunhosend_emailopcional
Exemplo:
EMAIL_AGENT_MCP_HOME=/tmp/email-agent-mcp-live \
AGENT_EMAIL_SEND_ALLOWLIST=/tmp/email-agent-mcp-live/send-allowlist.json \
npm run launch:prep:smoke -- --live-write --send-to beta@usejunior.com
A seleção padrão de candidato seguro procura por notifications@github.com na caixa de entrada para que você possa ensaiar o fluxo de gravação em uma mensagem pública segura em vez de correspondência de clientes.
Se o nome do status da sua caixa de entrada não for um endereço de e-mail, passe --reply-sender <email> ou defina EMAIL_AGENT_MCP_REPLY_SENDER para que o script possa encontrar uma mensagem enviada por você mesmo para a verificação de resposta a rascunho.
Referência de Ferramentas
Perfis de escopo
Defina EMAIL_AGENT_MCP_SCOPE_PROFILE antes de configurar e iniciar o servidor para
escolher as permissões expostas a um agente. O padrão é full para compatibilidade
retroativa.
| Perfil | Escopos delegados da Microsoft | Ferramentas expostas |
|---|---|---|
observe | Mail.Read, User.Read, offline_access | Ferramentas de e-mail somente leitura, menos list_inbox_rules (veja abaixo) |
full (padrão) | Mail.Read, Mail.ReadWrite, Mail.Send, MailboxSettings.ReadWrite, User.Read, offline_access | Todas as ferramentas |
Para uma implantação somente observação, defina o perfil tanto na configuração quanto no runtime para que o consentimento OAuth e a lista de ferramentas MCP concordem:
export EMAIL_AGENT_MCP_SCOPE_PROFILE=observe
npx email-agent-mcp configure
npx email-agent-mcp serve
Os escopos de observe são um subconjunto estrito deliberado dos de full. É isso que
torna o perfil adotável: um locatário que já consentiu com o conjunto completo
concede observe silenciosamente, então alternar full → observe não exige novo consentimento.
Alternar observe → full exige um novo consentimento interativo, porque
solicita escopos que nunca foram concedidos.
Pela mesma razão, observe não expõe list_inbox_rules. O Graph bloqueia
/mailFolders/inbox/messageRules atrás de MailboxSettings, e o Entra trata
MailboxSettings.Read como um escopo distinto do
full's
MailboxSettings.ReadWrite em vez de implicado por ele. Solicitá-lo quebraria
a propriedade de subconjunto e forçaria um novo consentimento em cada implantação observe — uma
solicitação de aprovação de administrador em locatários que restringem o consentimento do usuário. Use full se você
precisar de visibilidade das regras da caixa de entrada.
Um valor de perfil inválido interrompe a inicialização em vez de conceder silenciosamente acesso mais amplo. Se as credenciais em cache não cobrirem os escopos do perfil, o servidor falha rapidamente com um erro acionável em vez de bloquear em um login interativo.
O que observe garante e não garante
observe sempre remove as ferramentas de escrita da superfície de ferramentas MCP, então um agente
não pode invocá-las. Essa parte vale em todos os lugares.
Ele apenas restringe o token OAuth em uma caixa de entrada que ainda não consentiu
com os escopos de escrita. O Entra emite um token de acesso que carrega todos os escopos que o usuário
ou locatário já consentiu para esse aplicativo — não apenas o subconjunto
solicitado no momento da aquisição do token. Então, se você apontar observe para uma caixa de entrada
anteriormente configurada como full, o token subjacente ainda carrega
Mail.ReadWrite e Mail.Send; apenas a superfície de ferramentas é reduzida.
Para um token genuíno de privilégio mínimo, consinta com observe a partir de uma caixa de entrada que
nunca recebeu os escopos de escrita — um configure novo contra um registro de
aplicativo cujas permissões delegadas param em Mail.Read/User.Read. Trate
a redução da superfície de ferramentas como defesa em profundidade, não como uma fronteira OAuth, a menos que
você controle a concessão.
Ferramentas
O perfil full expõe 26 ferramentas MCP; observe omite toda ferramenta cuja ação
seja marcada como mutação de caixa de entrada:
| Ferramenta | Descrição | Tipo |
|---|---|---|
list_emails | Lista e-mails recentes com filtragem | leitura |
read_email | Lê o conteúdo completo do e-mail como markdown, ou HTML bruto com format: "html" | leitura |
search_emails | Pesquisa de texto completo nas caixas de entrada | leitura |
list_mailboxes | Enumera caixas de entrada configuradas, seu status e a padrão | leitura |
get_mailbox_status | Status da conexão e avisos | leitura |
get_thread | Contexto completo da conversa | leitura |
list_attachments | Lista metadados de anexos de um e-mail | leitura |
download_attachment | Baixa um anexo de arquivo como base64 | leitura |
send_email | Envia novo e-mail (controlado por lista de permissões) | escrita |
reply_to_email | Responde dentro da conversa (controlado por lista de permissões no envio) | escrita |
create_draft | Cria rascunho de e-mail | escrita |
update_draft | Atualiza o conteúdo do rascunho | escrita |
send_draft | Envia um rascunho salvo | escrita |
list_scheduled_sends | Lista envios agendados pendentes mantidos pelo provedor (Microsoft 365) | leitura |
cancel_scheduled_send | Cancela um envio agendado pendente (Microsoft 365) | destrutiva |
label_email | Aplica rótulos/categorias | escrita |
flag_email | Marca/desmarca e-mails com sinalizador | escrita |
mark_read | Marca como lido/não lido | escrita |
move_to_folder | Move entre pastas | escrita |
delete_email | Exclui (exige env do operador + sinalizador do chamador) | destrutiva |
list_folders | Lista recursivamente pastas e caminhos calculados (Microsoft 365) | leitura |
create_folder | Cria uma subpasta personalizada (Microsoft 365) | escrita |
delete_folder | Exclui uma pasta personalizada (exige env do operador + sinalizador do chamador); pastas do sistema são protegidas (Microsoft 365) | destrutiva |
list_inbox_rules | Lista regras de caixa de entrada do servidor (Microsoft 365) | leitura |
create_inbox_rule | Cria uma regra de caixa de entrada segura persistente; encaminhamento, redirecionamento, exclusão e descarte para Itens Excluídos são bloqueados (Microsoft 365) | escrita |
delete_inbox_rule | Exclui uma regra de caixa de entrada do servidor (exige env do operador + sinalizador do chamador) (Microsoft 365) | destrutiva |
Esta é uma superfície de ferramentas compartilhada entre provedores. Embora label_email,
flag_email, mark_read, move_to_folder e delete_email sejam anunciadas,
o adaptador Gmail intencionalmente não implementa essas capacidades de mutação.
Elas falham fechadas antes de qualquer solicitação de mutação Gmail: ações não suportadas retornam
NOT_SUPPORTED, enquanto a exclusão pode parar primeiro no portão padrão do operador DELETE_DISABLED.
O gmail.readonly padrão mais a concessão gmail.compose não
autorizariam essas mutações também; não adicione gmail.modify para tentar tornar as
ferramentas disponíveis. Elas permanecem disponíveis apenas para provedores cujos adaptadores e
concessões as suportam.
Cada linha retornada por list_emails, search_emails e get_thread, e a
resposta read_email, carrega um booleano isDraft sempre presente. isDraft: true
significa que a mensagem é um rascunho não enviado: ela não foi enviada, e seu receivedAt
é metadado fornecido pelo provedor em vez de evidência de entrega. O campo nunca é
omitido, então um agente consumidor pode distinguir "não é um rascunho" de "status de rascunho não
informado" — mas observe que false afirma apenas que o provedor não marcou a mensagem
como um rascunho não enviado, não que o proprietário da caixa de entrada a enviou (correspondência recebida também é
false). Rascunhos aparecem de outra forma em listagens e resultados de pesquisa como antes.
O gerenciamento de pastas e regras de caixa de entrada exige consentimento do Microsoft Graph MailboxSettings.ReadWrite. Conexões existentes de caixa de entrada da Microsoft devem reconsentir após a atualização. O Gmail usa rótulos em vez de pastas hierárquicas/regras Exchange do servidor, então essas seis ferramentas retornam NOT_SUPPORTED para caixas de entrada do Gmail.
Formatos de corpo
Corpos atravessam o fio como markdown por padrão em ambas as direções. Esse padrão é deliberado — markdown é eficiente em tokens, e uma leitura rotineira deve permanecer barata. Ambas as direções podem optar por sair dele.
Escrita — send_email, reply_to_email, create_draft e update_draft
aceitam um format opcional:
format | Comportamento |
|---|---|
markdown (padrão) | Renderizado para HTML via marked (GFM, breaks: true). HTML bruto embutido no markdown é preservado. |
html | Passagem direta — seu HTML é enviado como está. |
text | Sem renderização; enviado como texto simples. |
html é passagem direta não sanitizada: sem sanitizador, sem lista de permissões, sem reescrita do
seu markup. CSS inline e tags arbitrárias sobrevivem até o fio — é isso que
torna possível e-mail estilizado, e significa que você é responsável pelo que enviar. A única
modificação padrão é o wrapper preto forçado abaixo; com force_black: false o corpo passa byte por byte.
Para markdown e html o HTML renderizado é envolvido em um
<div style="color: #000000;"> para que o modo escuro do Outlook não transforme o texto
em branco sobre branco.
Arquivos de corpo — send_email, create_draft e update_draft também aceitam
body_file: um caminho para um arquivo .md, .html ou .txt (lido em relação a
EMAIL_MCP_SAFE_DIR, por padrão o diretório de trabalho do processo, além de quaisquer
raízes de AGENT_EMAIL_ALLOWED_DIRS) usado como corpo
em vez de body. Um arquivo de corpo .md pode
abrir com um bloco de frontmatter YAML:
Para update_draft, body e body_file são permitidos apenas em um rascunho que não seja de resposta
e exigem replace_body: true; o corpo armazenado é então substituído
por completo. Corpos de rascunhos de resposta não podem ser editados com segurança porque incluem
histórico citado montado pelo provedor, então crie um novo rascunho. Assunto,
destinatário e anexos permanecem disponíveis em rascunhos de resposta.
---
to: alex@example.com
subject: Quarterly summary
format: html
force_black: false
---
<p>The body starts after the closing delimiter.</p>
As chaves reconhecidas são to, cc, subject, reply_to, draft, format e
force_black (draft: true transforma uma chamada send_email em um salvamento de rascunho). Um
valor de frontmatter substitui o parâmetro de ferramenta de mesmo nome. O frontmatter é
analisado apenas de arquivos .md, e a extensão do arquivo nunca seleciona o formato —
sem um parâmetro de ferramenta format explícito, até mesmo um arquivo de corpo .html recebe a
renderização markdown padrão; passe format: "html" para passagem direta.
Leitura — read_email aceita um format opcional de markdown (padrão)
ou html:
{ "id": "AAMkAD...", "format": "html" }
format: "html" retorna o HTML bruto do corpo da mensagem verbatim. Use-o quando
precisar de estilos que o markdown não pode carregar — color, background-color,
text-decoration, <u> — por exemplo, para alterar uma frase de um corpo formatado
e deixar o resto intacto. Pelo caminho markdown, esse estilo é silenciosamente
destruído na saída.
Dois campos retornam com ele:
bodyFormat— sempre presente:markdown,htmloutext. Você recebetextquando solicitouhtmlmas a mensagem não tem parte HTML, caso em que o corpo em texto simples é retornado. Verifique isso antes de escrever um corpo de volta.bodyTruncated— presente etruesomente se o corpo excedeu o orçamento de resposta de 256 KB paraformat: "html"(o caminho markdown é ilimitado, como antes). Não escreva um corpo truncado de volta em um rascunho.
HTML bruto custa muito mais tokens do que sua redução em markdown, então deixe o padrão
intacto a menos que precise do estilo. strip_quoted_history e strip_signatures
são transformações de texto em formato markdown e não são aplicadas quando format é html —
o HTML bruto é retornado intocado.
Escrevendo de volta. Passe format: "html" e force_black: false:
{ "draft_id": "AAMkAD...", "body": "<edited html>", "format": "html", "force_black": false }
force_black assume como padrão true, que envolve qualquer HTML que você enviar em um
<div style="color: #000000;">. Isso é correto para HTML que você mesmo criou,
mas em um corpo que você acabou de ler, ele aninha mais um wrapper a cada ciclo —
após quinze revisões, você tem quinze divs aninhados. Com force_black: false, os
bytes sobrevivem à ida e volta intactos.
Envio agendado
send_email e send_draft aceitam scheduled_send_at, um timestamp ISO 8601 futuro
com fuso horário explícito. O Microsoft 365 mantém a mensagem
no lado do servidor, então a entrega sobrevive à saída deste processo. Use o
messageId retornado com cancel_scheduled_send enquanto estiver pendente, ou inspecione itens
pendentes com list_scheduled_sends. Essa listagem cobre mensagens que você agendou
do próprio Outlook, não apenas as agendadas por este servidor — o Outlook
estaciona a mensagem retida onde quiser (frequentemente em Itens Excluídos), então a descoberta varre a
caixa de correio em vez de uma pasta, e relata apenas envios cujo horário ainda está por vir.
O Microsoft Graph altera o ID da mensagem quando o rascunho retido vai para Itens Enviados,
então o ID retornado é um identificador de gerenciamento pré-entrega, não um ID permanente de mensagem
enviada. A API pública do Gmail não expõe envio agendado; todas as superfícies
de envio agendado retornam NOT_SUPPORTED para Gmail, enquanto envios imediatos permanecem
inalterados.
Anexos de saída
send_email, reply_to_email, create_draft e update_draft aceitam um
array opcional de attachments. Cada entrada aceita um arquivo path em sandbox (lido
em relação a EMAIL_MCP_SAFE_DIR, por padrão o diretório de trabalho do processo, além de
quaisquer raízes de AGENT_EMAIL_ALLOWED_DIRS — veja abaixo) ou
base64 inline, além de substituições opcionais de filename / mimeType:
{
"to": "alice@example.com",
"subject": "Signed agreement",
"body": "Attached as requested.",
"attachments": [
{ "path": "./out/agreement.pdf" },
{ "base64": "iVBORw0KGgo...", "filename": "screenshot.png" }
]
}
Arquivos são limitados a 25MB cada; o Microsoft Graph adicionalmente limita envios inline
a ~3MB no total (arquivos maiores precisam de uma sessão de upload — ainda não suportada). Para
update_draft, omitir attachments preserva os arquivos existentes do rascunho;
passar um array (mesmo vazio) os substitui.
Anexando arquivos de fora do diretório de trabalho — defina
AGENT_EMAIL_ALLOWED_DIRS como uma lista separada por delimitadores de diretórios
absolutos (: no macOS/Linux, ; no Windows; um ~ inicial é expandido) que
attachments[].path e body_file também podem ler:
{
"mcpServers": {
"email-agent-mcp": {
"command": "npx",
"args": ["-y", "@usejunior/email-agent-mcp"],
"env": { "AGENT_EMAIL_ALLOWED_DIRS": "~/Downloads:/Volumes/Shared/Contracts" }
}
}
}
Como o caminho de um chamador é resolvido — as duas regras abaixo aparecem como
FILE_NOT_FOUND, que é fácil de interpretar erroneamente como um arquivo ausente:
| Caminho que você passa | Resolve contra | Encontra um arquivo em uma raiz permitida? |
|---|---|---|
contract.pdf | EMAIL_MCP_SAFE_DIR (padrão: cwd) | ❌ caminhos relativos nunca buscam nas raízes extras |
~/Downloads/contract.pdf | EMAIL_MCP_SAFE_DIR — o ~ não é expandido | ❌ |
/Users/you/Downloads/contract.pdf | cada raiz por vez | ✅ |
A abreviação ~ é expandida em AGENT_EMAIL_ALLOWED_DIRS (a configuração do
operador), mas não em attachments[].path ou body_file (o argumento do
chamador) — passe-os como caminhos absolutos. E um caminho relativo é deliberadamente
confinado ao diretório seguro: buscar em cada raiz permitida por um
contract.pdf simples anexaria silenciosamente qualquer cópia que existisse primeiro.
Cada raiz é canonicalizada com realpath antes da verificação de contenção: uma
raiz na lista de permissões que é em si um symlink resolve para sua localização real, uma raiz
que não pode ser canonicalizada não autoriza nada, e um symlink que escapa de toda
raiz ainda é rejeitado. Não definido (o padrão) mantém o diretório de trabalho como a
única raiz — é por isso que um agente que não consegue acessar um arquivo deve pedir que você
coloque seu diretório na lista de permissões em vez de copiar documentos confidenciais para uma árvore de trabalho git.
Colocar um diretório na lista de permissões confia em todos que podem escrever nele. Validação e
abertura são operações separadas em um caminho, então um principal que pode substituir um diretório
dentro de uma raiz permitida entre as duas ainda pode redirecionar a leitura;
apenas coloque na lista de permissões raízes cujos ancestrais não sejam graváveis por usuários não confiáveis. O
arquivo final é aberto com O_NOFOLLOW, então o arquivo em si não pode ser trocado por um
symlink após a validação.
Suporte do Provedor
| Provedor | Status | Pacote |
|---|---|---|
| Microsoft 365 (Graph API) | Totalmente suportado | @usejunior/provider-microsoft |
| Gmail | Suportado via OAuth interativo por CLI (cliente padrão ou seu próprio) ou configuração manual de refresh-token | @usejunior/provider-gmail |
Use email-agent-mcp configure --provider gmail para executar o fluxo OAuth no navegador local, ou adicione um arquivo de token de caixa de correio manual em ~/.email-agent-mcp/tokens/. Veja Configuração do Gmail abaixo e packages/provider-gmail/README.md.
Configuração do Gmail
O Gmail tem dois caminhos OAuth suportados. Ambos terminam com o mesmo resultado: um refresh token na sua máquina, e chamadas à API do Gmail indo diretamente da sua máquina para o Google.
| Caminho | Comando | Projeto Google Cloud necessário? |
|---|---|---|
| Cliente OAuth padrão | email-agent-mcp configure --provider gmail | Não |
| Traga sua própria chave (BYOK) | mesmo comando mais --client-id / --client-secret | Sim, seu |
Recomendado por enquanto: BYOK. Nosso cliente OAuth padrão ainda está no status de publicação "Teste" do Google enquanto a verificação está em andamento, o que o limita a 100 usuários de teste registrados e mostra o aviso "O Google não verificou este aplicativo" durante o consentimento. A verificação para o escopo restrito do Gmail exige uma avaliação de segurança CASA e leva várias semanas; o progresso é acompanhado em issue #112. O BYOK contorna o limite compartilhado de 100 usuários e coloca o status de publicação do aplicativo sob seu controle; seu próprio aplicativo ainda tem as restrições de Teste do Google até que você o publique.
Outras razões para escolher BYOK: cota de API dedicada, sua própria política de privacidade e
status de verificação, e nenhuma dependência do broker hospedado em
https://oauth.usejunior.com.
Escopos solicitados
O Email Agent MCP solicita exatamente estes dois escopos do Gmail por padrão:
https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/gmail.compose
gmail.readonly é necessário para ler mensagens e threads;
gmail.compose gerencia rascunhos e envio, mas não autoriza
users.threads.get ou users.messages.get. A concessão padrão não inclui
gmail.modify. Separadamente, o adaptador do Gmail intencionalmente deixa alterações de rótulos,
alterações de estado de leitura, movimentações, lixeira e operações de exclusão sem suporte,
então essas ferramentas falham fechadas com NOT_SUPPORTED. Adicione ambos os escopos à sua tela
de consentimento OAuth.
Implantações que definem explicitamente GMAIL_OAUTH_SCOPES devem atualizá-lo para os dois
escopos separados por espaço acima. Novas autorizações e autorizações repetidas
devem re-consentir com o novo par de escopos. Arquivos de caixa de correio existentes e seus metadados
de refresh-token armazenados permanecem inalterados.
BYOK: crie seu próprio cliente OAuth do Google
- Crie um projeto no Console do Google Cloud, ou selecione um existente.
- Ative a API do Gmail em APIs & Serviços → Biblioteca → Gmail API → Ativar.
- Configure a tela de consentimento OAuth em APIs & Serviços → Tela de consentimento OAuth:
- Tipo de usuário Externo para uma conta pessoal
@gmail.com, ou Interno se você estiver no Google Workspace e apenas sua própria organização precisar de acesso. - Adicione ambos
https://www.googleapis.com/auth/gmail.readonlyehttps://www.googleapis.com/auth/gmail.compose. - Enquanto o aplicativo estiver em Teste, adicione seu próprio endereço de Gmail em Usuários de teste, ou o consentimento será recusado.
- Tipo de usuário Externo para uma conta pessoal
- Crie o cliente OAuth em APIs & Serviços → Credenciais → Criar
credenciais → ID do cliente OAuth. Escolha o tipo de aplicativo Aplicativo de desktop.
Desktop é obrigatório:
configureinicia um listener descartável em uma porta loopback efêmera (http://127.0.0.1:<port>/oauth2callback), e apenas clientes Desktop permitem que o Google aceite uma porta loopback arbitrária sem pré-registrar o URI de redirecionamento exato. Um cliente de aplicativo Web falhará comredirect_uri_mismatch. - Copie o ID do cliente e o segredo do cliente.
BYOK: entregue as credenciais ao email-agent-mcp
Passe ambas as partes como flags:
npx email-agent-mcp configure \
--provider gmail \
--mailbox personal \
--client-id YOUR_GOOGLE_CLIENT_ID \
--client-secret YOUR_GOOGLE_CLIENT_SECRET
Ou defina as duas variáveis de ambiente com namespace e omita as flags:
export AGENT_EMAIL_GMAIL_CLIENT_ID=YOUR_GOOGLE_CLIENT_ID
export AGENT_EMAIL_GMAIL_CLIENT_SECRET=YOUR_GOOGLE_CLIENT_SECRET
npx email-agent-mcp configure --provider gmail --mailbox personal
Ambas as partes são obrigatórias. Fornecer apenas uma sai com erro em vez de silenciosamente cair para o cliente padrão. Fornecer nenhuma seleciona o cliente OAuth padrão.
Seu navegador abre a tela de consentimento do Google, a CLI captura o callback na
loopback, troca o código com PKCE e escreve a caixa de correio em
~/.email-agent-mcp/tokens/<safe-key>.json com "source": "byok" ao lado
do seu clientId, clientSecret e o refreshToken resultante. Atualizações de
token então vão direto para o endpoint de token do Google; nenhum broker está envolvido.
Re-executar configure para uma caixa de correio já salva reutiliza as credenciais
salvas, então você só passa as flags uma vez. Passar --client-id e
--client-secret para uma caixa de correio previamente configurada contra o cliente
padrão a migra para BYOK.
BYOK: evite que a concessão expire após 7 dias
O Google expira refresh tokens após 7 dias enquanto seu app OAuth estiver no
status Testing (Teste) de publicação, o que aparece como um prompt de
reautenticação cerca de uma vez por semana. email-agent-mcp status avisa quando uma
caixa de entrada está se aproximando dessa janela. Publicar seu app (OAuth
consent screen → Publish app) remove a expiração de 7 dias. Como você é o
dono do app e seu único usuário, o limite de 100 usuários de teste não se
aplica a você de qualquer forma.
Desconectar o Gmail e revogar o acesso
Desconectar tem duas partes independentes:
- Pare qualquer processo
email-agent-mcpem execução. No Finder, abra~/.email-agent-mcp/tokens/, identifique o único arquivo JSON da caixa de entrada que você pretende desconectar e mova exatamente esse arquivo para a Lixeira. Não abra, cole ou compartilhe seu conteúdo, e não exclua o diretório inteiro~/.email-agent-mcpse outras caixas de entrada estiverem configuradas. Se você definiuEMAIL_AGENT_MCP_HOME, use a pastatokens/desse diretório. - Abra Conexões de terceiros da Conta Google, selecione Email Agent MCP (ou o nome do seu aplicativo BYOK) e remova seu acesso.
Excluir o arquivo local impede que esta instalação use a credencial salva.
Remover a conexão da Conta Google revoga a concessão no Google. Execute
email-agent-mcp status depois para confirmar que a caixa de entrada não está mais
configurada.
Padrões de Segurança
O Agent Email vem com padrões restritivos que você afrouxa conforme necessário:
- Lista de permissão de envio: vazia por padrão — os agentes não podem enviar e-mails até você adicionar destinatários
- Lista de permissão de recebimento: aceita tudo por padrão — controla quais remetentes acionam o watcher
- Exclusão desabilitada: os agentes não podem excluir e-mails por padrão. Duas condições devem ser satisfeitas:
- o operador define
AGENT_EMAIL_DELETE_ENABLED=trueno ambiente do processo email-agent-mcp (eAGENT_EMAIL_HARD_DELETE_ENABLED=truepara exclusão permanente). Reinicialização necessária após a alteração. - o chamador passa
user_explicitly_requested_deletion: truena chamada da ferramenta.
- o operador define
- Sanitização de erros: chaves de API, caminhos de arquivo e stack traces são removidos das respostas de erro
- Sandbox de arquivos do corpo: sem travessia de
../, sem symlinks, detecção de binários - Proteção contra entrega duplicada: ativada por padrão — um envio, resposta ou envio de rascunho idêntico repetido em até 15 minutos é recusado em vez de ser entregue duas vezes
Proteção contra entrega duplicada
Os endpoints de envio dos provedores (Graph POST /sendMail, Gmail users.messages.send) não aceitam
chave de idempotência, então o Agent Email despacha cada entrega exatamente uma vez e nunca
tenta novamente automaticamente. Isso impede que a biblioteca duplique uma mensagem. Não impede
o chamador: um agente cujo resultado da ferramenta foi perdido — um contexto compactado, um
transporte interrompido, um supervisor reiniciando a rodada, uma pessoa tentando novamente algo que
parecia travado — reproduz a mesma instrução aprovada, e a segunda chamada parece exatamente igual à
primeira.
send_email, reply_to_email e send_draft registram, portanto, cada despacho em um
registro em processo, com chave baseada em um resumo das entradas efetivas da ação — caixa de
entrada, destinatários, assunto, corpo renderizado, conteúdo dos anexos e o pai da resposta ou o ID
do rascunho. (Entradas efetivas, não bytes finais do fio: um provedor pode transformar uma mensagem
no caminho de saída, e o Graph, por exemplo, trunca um assunto em 255 caracteres, então duas
entradas diferentes podem sair como e-mails idênticos. A proteção detecta uma chamada de ferramenta
reproduzida, que é o que realmente acontece.) Uma repetição dentro da janela é recusada antes de o
despacho ser enviado:
| Código | Significado | O que fazer |
|---|---|---|
DUPLICATE_SEND_IN_FLIGHT | Uma entrega idêntica ainda não retornou | Aguarde a primeira chamada |
DUPLICATE_SEND_BLOCKED | Uma entrega idêntica já foi bem-sucedida | Pare — a resposta carrega o messageId original |
DUPLICATE_SEND_UNRESOLVED | Uma entrega idêntica terminou de forma ambígua | Verifique os Itens Enviados antes de reenviar |
Uma falha que prova que nada foi entregue — qualquer código derivado de 4xx, um 429 ou uma falha de conexão — libera o registro imediatamente, então reenviar após uma rejeição nunca é bloqueado. Qualquer outra coisa, incluindo um código de um provedor que não vimos, é mantida como não resolvida: uma mensagem retida indevidamente custa um reenvio bloqueado; uma liberada indevidamente custa uma duplicata na caixa de entrada de alguém.
Para enviar a mesma mensagem novamente de propósito, passe allow_duplicate: true. É um
desvio incondicional por solicitação — uma reprodução que também carrega a flag despacha
novamente, porque a flag afirma que uma pessoa decidiu sobre esse envio. A tentativa forçada
é registrada junto com a anterior, em vez de substituí-la, então se a substituição for
rejeitada, a entrega original ainda recusa uma reprodução comum.
Os registros são limitados a uma caixa de entrada: mailbox quando o chamador fornece
uma, caso contrário, a instância do provedor. Os operadores podem alterar a janela com
AGENT_EMAIL_DUPLICATE_SEND_WINDOW_MS (padrão 900000); 0 desativa a proteção
inteiramente.
O registro vive no processo do servidor e na memória. Ele fecha a janela de reprodução que realmente acontece — uma nova tentativa dentro de um servidor em execução — e não sobrevive ao reinício desse servidor.
Pacotes
| Pacote | Descrição |
|---|---|
@usejunior/email-core | Ações principais de e-mail, mecanismo de conteúdo, segurança e interfaces de provedor |
@usejunior/email-mcp | Adaptador de servidor MCP, CLI e watcher |
@usejunior/provider-microsoft | Provedor de e-mail da API Microsoft Graph |
@usejunior/provider-gmail | Provedor de e-mail da API Gmail |
email-agent-mcp | Wrapper de distribuição (npx email-agent-mcp) |
@usejunior/email-agent-mcp | Wrapper de compatibilidade, publicado em conjunto; use email-agent-mcp para novas instalações |
Sinais de Qualidade e Confiança
- CI é executado em cada pull request e push para main (lint, typecheck, testes no Node 20 + 22)
- Varredura de segurança CodeQL e Semgrep
- Cobertura publicada no Codecov
- Aplicação de rastreabilidade OpenSpec via
npm run check:spec-coverage - Mais de 300 testes no conjunto
- Mantenedor: Steven Obiajulu
Arquitetura
email-agent-mcp/
├── packages/
│ ├── email-core Core actions, content engine, security
│ ├── email-mcp MCP server adapter, CLI, watcher
│ ├── provider-microsoft Microsoft Graph provider
│ ├── provider-gmail Gmail API provider
│ └── email-agent-mcp Distribution wrapper (npx entry point)
├── openspec/ Spec-driven development
└── scripts/ CI and validation scripts
Lançamentos
Lançamento orientado por tags via GitHub Actions com publicação confiável npm OIDC. Todos os 6 pacotes são publicados em ordem de dependência com --provenance, depois server.json é publicado no Registro MCP oficial com mcp-publisher.
FAQ
Isso funciona com o Claude Code?
Sim. Execute npx email-agent-mcp para iniciar o servidor MCP e configure-o nas configurações do seu Claude Code.
Os agentes podem enviar e-mails sem minha permissão?
Não. A lista de permissão de envio está vazia por padrão. Os agentes não podem enviar nenhum e-mail até você configurar explicitamente os destinatários permitidos.
Isso armazena minhas credenciais de e-mail?
Os tokens OAuth são gerenciados pelo MSAL (Microsoft) e armazenados no chaveiro do seu sistema operacional ou em arquivos de configuração locais em ~/.email-agent-mcp/. O Agent Email nunca armazena senhas em texto puro.
Posso conectar várias caixas de entrada?
Sim. Você pode configurar Microsoft 365 e Gmail simultaneamente. As ações de leitura usam sua caixa de entrada principal por padrão; as ações de escrita exigem especificar uma caixa de entrada quando várias estão configuradas.
O CLI do OpenClaw rejeita minha configuração com "Unrecognized key: mcp"
O CLI do OpenClaw e o app macOS podem ser versões diferentes. O app (que executa o gateway) pode suportar chaves de configuração que o CLI ainda não reconhece. Atualize o CLI: cd ~/Projects/NemoClaw && npm install openclaw@latest. Alternativamente, reinicie o gateway diretamente: launchctl kickstart -k gui/501/ai.openclaw.gateway.
O watcher inicia, mas encontra zero caixas de entrada
As credenciais das caixas de entrada são armazenadas em ~/.email-agent-mcp/tokens/. Se este diretório estiver vazio, execute npx email-agent-mcp ou npm run dev:configure para autenticar via OAuth. O watcher sairá sem caixas de entrada para consultar até que pelo menos uma seja configurada.
O OpenClaw diz "Demo mode -- run email-agent-mcp configure to connect"
O servidor MCP está em execução, mas não tem credenciais reais de caixa de entrada. Execute npx email-agent-mcp para concluir a configuração interativa de OAuth e reinicie o gateway do OpenClaw para que o servidor MCP se reconecte com tokens válidos.
Token expirou após uma semana mesmo eu tendo acabado de autenticar
Os refresh tokens da Microsoft normalmente duram 90 dias, mas seu locatário do Azure AD pode impor durações mais curtas. O código usa MSAL com persistência no chaveiro do sistema operacional (@azure/identity-cache-persistence), que lida com a renovação silenciosa de tokens automaticamente. Se o MSAL relatar interaction_required ou invalid_grant, execute novamente npx email-agent-mcp para reautenticar. Causas comuns: políticas de acesso condicional, requisitos de reverificação de MFA ou políticas de duração de token configuradas pelo administrador.
O bot do Telegram do OpenClaw recebe mensagens, mas não responde
Verifique se o canal do Telegram está saudável com openclaw status. Se o canal mostrar OK, mas nenhuma resposta voltar, verifique se: (1) seu ID de usuário do Telegram está em channels.telegram.allowFrom em openclaw.json, (2) existe uma vinculação correspondente a channel: "telegram" e (3) o gateway foi reiniciado após alterações de configuração. Para bots de um único dono, use dmPolicy: "allowlist" com IDs allowFrom explícitos em vez de depender de aprovações de pareamento.
Desenvolvimento
npm ci
npm run build
npm run lint --workspaces --if-present
npm run test:run
npm run check:spec-coverage
Veja Também
- Safe DOCX Suite — edição cirúrgica de documentos do Word com agentes de codificação
- Open Agreements — preencha modelos jurídicos padrão com agentes de codificação
Privacidade
O Agent Email é executado inteiramente na sua máquina local. As credenciais de e-mail são armazenadas no chaveiro do seu sistema operacional (MSAL) e em arquivos de configuração locais. Nenhum conteúdo de e-mail é enviado a servidores externos pelo próprio Agent Email.