Skip to main content

subagent-python

Le SDK Python de Subagent Mail : des boîtes mail pour agents IA. Votre agent crée sa boîte, écrit, lit ses fils et répond avec sa propre adresse. Le serveur applique les règles d'envoi : montée progressive, créneaux, validation humaine, désinscription.

  • Une méthode par opération du serveur (64), mêmes noms et mêmes arguments que les outils du MCP.
  • Aucune dépendance : bibliothèque standard seulement, Python 3.9 ou plus.
  • Typé : arguments et résultats sont tirés des schémas du serveur.
  • Généré depuis le registre d'opérations du serveur, jamais écrit à la main.

Installer

pip install subagent-mail

Démarrer

1. Une clé

Sans clé, une seule opération est ouverte : sign_up. Elle rend une clé, affichée une seule fois, et une boîte sur subagentmail.fr. Votre humain reçoit un code à 6 chiffres par e-mail ; verify ouvre l'envoi.

from subagent_mail import Subagent

client = Subagent()  # lit SUBAGENT_KEY ; sans clé, seule sign_up est ouverte

inscription = client.sign_up(username="atelier-exemple", human_email="marie@exemple.fr")
print(inscription["api_key"])           # affichée une seule fois : rangez-la
print(inscription["inbox"]["address"])  # atelier-exemple@subagentmail.fr

client.verify(otp_code="482913")        # le code reçu par votre humain

Vous avez déjà une clé ? Rangez-la hors du code, le client la lit seul :

export SUBAGENT_KEY="sak_…"

2. Où en est la boîte

inbox_status est le point de départ de toute session : l'espace, les permissions de la clé, le créneau d'envoi, et pour chaque boîte son quota du jour.

etat = client.inbox_status()
boite = etat["inboxes"][0]
print(boite["address"], boite["quota"]["remaining_today"])

3. Un premier envoi

Un envoi de test ne part qu'à l'humain de l'espace ou à une autre de ses boîtes : remplacez l'adresse par la vôtre.

envoi = client.send_email(
    inbox_id=boite["id"],
    to="marie@exemple.fr",
    subject="Premier message",
    text="Bonjour Marie,\n\nCeci est mon premier message.\n",
    test=True,                            # à soi-même seulement
    requires_approval=True,               # reste en brouillon jusqu'à la validation d'un humain
    idempotency_key="premier-message-1",  # rejouer cet appel ne crée pas de doublon
)
print(envoi["message"]["status"])  # draft

Sans requires_approval, le message entre en file et part dans le créneau d'envoi, selon le quota du jour de la boîte. estimated_send_at donne l'heure de départ au plus tôt. Un message en file n'est pas une erreur : ne le renvoyez pas.

Les opérations

Famille Opérations
Inscription sign_up, verify, attach_human
Boîtes inbox_status, activity_report, list_inboxes, create_inbox, update_inbox, delete_inbox, request_inbox_review
Domaines inspect_domain, add_domain, verify_domain, list_domains, domain_quality, remove_domain
Envoi send_email, reply_to_thread
Fils list_threads, get_thread, classify_thread, close_thread, get_message
Brouillons list_drafts, update_draft, approve_message, cancel_message
Pièces jointes attach_files, remove_attachment, get_attachment
Liste de blocage add_suppression, remove_suppression, list_suppressions
Contacts et audiences list_contacts, get_contact, save_contact, set_contact_audiences, list_audiences, get_audience, save_audience, import_contacts, remove_audience_contact
Campagnes list_campaigns, get_campaign, save_campaign, preview_campaign, campaign_action, campaign_metrics, campaign_history, list_campaign_templates, save_campaign_template
Main courante list_events, workspace_snapshot
Forfait billing_status, subscribe, cancel_subscription
Espace et accès get_settings, update_settings, list_keys, create_key, revoke_key, set_webhook, remove_webhook, close_space

Arguments, résultats et un exemple par méthode : reference.md. Sur le site : documentation · openapi.json · llms.txt.

Les résultats sont des dictionnaires typés (TypedDict) : envoi["message"]["id"]. Le serveur peut ajouter des champs : un champ inconnu ne casse rien.

Quand le serveur refuse

Un refus n'est pas une panne. Il lève SubagentError, qui porte un code stable, un message en français et une piste (hint) qui dit quoi faire. La piste se suit, elle ne se contourne pas.

from subagent_mail import SubagentError

try:
    client.approve_message(message_id=envoi["message"]["id"])
except SubagentError as refus:
    print(refus.code)     # forbidden : la clé d'un agent ne porte pas approve
    print(refus.message)  # la phrase du serveur, en français
    print(refus.hint)     # ce qu'il faut faire
    print(refus.status)   # 403

Un agent ne valide jamais son propre brouillon : approve_message demande la permission approve, que la clé rendue par sign_up ne porte pas.

Les refus les plus courants :

code HTTP Ce qui s'est passé Que faire
space_unverified 403 L'espace n'est pas vérifié : ses boîtes reçoivent, mais n'envoient pas. Demander à l'humain le code à 6 chiffres, puis appeler verify. S'il n'a rien reçu, ou si aucun e-mail n'est rattaché à l'espace : attach_human.
trial_limit 429 Sur un serveur réglé sans forfaits, le nombre de destinataires distincts permis depuis le domaine commun est atteint. Suivre la piste : elle donne le moment où l'envoi reprend.
recipient_suppressed 422 Le destinataire est bloqué : désinscription, plainte, adresse morte ou blocage manuel. Ne plus écrire à cette adresse, depuis aucune boîte.
duplicate_recipient 409 Cette boîte a déjà écrit un premier message à ce destinataire dans les 30 derniers jours. Répondre dans le fil donné par la piste, avec reply_to_thread.
key_daily_cap 429 Le plafond de messages par jour de la clé est atteint. Reprendre le lendemain, à partir de 0 h, heure de Paris.
inbox_suspended 409 Le coupe-circuit a suspendu la boîte. La raison est dans le message. Vérifier la liste de destinataires. La reprise est manuelle, par un administrateur de Subagent : l'humain la demande avec request_inbox_review.
unresolved_placeholder 422 Un champ entre doubles accolades est resté dans le sujet ou le texte. Remplacer chaque champ par sa valeur. Seul {{unsubscribe_url}} est accepté.
idempotency_conflict 409 La même idempotency_key a déjà servi pour un contenu différent. Même message : réutiliser la clé telle quelle. Nouveau message : en prendre une nouvelle.
forbidden 403 La clé ne porte pas la permission que l'outil demande. Pour approve : le geste revient à l'humain, depuis son assistant branché à https://api.subagent.fr/connect. La piste le dit.

Tous les codes (84) : reference.md, ou subagent_mail.CODES.

SubagentConnectionError est l'autre cas : le serveur n'a pas répondu (réseau, délai dépassé). Rien ne dit alors si l'appel a abouti.

Idempotence

Passez une idempotency_key à chaque envoi qu'un agent pourrait rejouer. Elle part dans l'en-tête Idempotency-Key.

premier = client.send_email(
    inbox_id=boite["id"], to="marie@exemple.fr", subject="Compte rendu", text="Bonjour Marie, …",
    test=True, idempotency_key="compte-rendu-12-octobre",
)
second = client.send_email(
    inbox_id=boite["id"], to="marie@exemple.fr", subject="Compte rendu", text="Bonjour Marie, …",
    test=True, idempotency_key="compte-rendu-12-octobre",
)
print(second["replayed"])  # True : rien de nouveau n'a été créé

Même clé, même contenu : le message déjà créé, avec replayed à vrai. Même clé, autre contenu : refus idempotency_conflict.

Le client ne réessaie seul que ce qui se rejoue sans risque : une lecture, ou un envoi qui porte une idempotency_key, et seulement quand le serveur n'a pas répondu. Un refus n'est jamais réessayé.

Asynchrone

AsyncSubagent a les mêmes méthodes, à attendre avec await.

import asyncio
from subagent_mail import AsyncSubagent

async def reponses_a_traiter():
    client = AsyncSubagent()
    fils = await client.list_threads(status="replied")
    return fils["items"]

print(asyncio.run(reponses_a_traiter()))

Réglages

Argument Par défaut Rôle
api_key variable SUBAGENT_KEY La clé sak_… de l'agent.
base_url https://api.subagent.fr, ou variable SUBAGENT_BASE_URL L'adresse du service.
timeout 30 Délai d'un appel, en secondes.
max_retries 2 Réessais quand le serveur ne répond pas, pour les seuls appels rejouables.

Une opération plus récente que ce SDK s'appelle par son nom : client.call("nom", {"argument": "valeur"}).

Tests

Les tests tournent contre un faux serveur local, généré depuis le même registre : il contrôle la clé, les permissions et chaque argument contre le schéma, et n'envoie rien.

python -m unittest discover -s tests

Pour essayer un script à la main sans toucher au service :

python tests/faux_serveur.py   # http://127.0.0.1:8787, clé sak_exemple_agent

Contribuer

Ce dépôt est généré depuis le registre d'opérations du serveur : une modification faite ici à la main serait écrasée à la génération suivante. Ouvrez un ticket plutôt qu'une demande de fusion.

Licence

MIT. Le serveur Subagent, lui, n'est pas ouvert : ces clients ne servent qu'avec une clé Subagent.

Metadata

Release files for subagent-mail 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for subagent-mail 0.1.0
File Size Uploaded Provenance Actions
subagent_mail-0.1.0.tar.gz 48.8 kB With provenance Details for subagent_mail-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for subagent-mail 0.1.0
File Interpreter ABI Platform Actions
subagent_mail-0.1.0-py3-none-any.whl Python 3 none any Details for subagent_mail-0.1.0-py3-none-any.whl

Total release size: 89.7 kB

Release files / subagent_mail-0.1.0.tar.gz

Download URL subagent_mail-0.1.0.tar.gz
Size 48.8 kB
Tags Source
SHA-256 checksum
How to use checksums
958dc9b710eea36b146a97ed3aa9281c2895e82fd705d6d92c3ac4486f33eb31
BLAKE2b-256 checksum
How to use checksums
1c50362e9792f9c329fd1e289067b466c7f01bbf37323e958c4727b23d92693e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / subagent_mail-0.1.0-py3-none-any.whl

Download URL subagent_mail-0.1.0-py3-none-any.whl
Size 40.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bd3944b3306f48ba0b5625c7f0d1cbc0c29211b15dc601abbf1f954a79495a7e
BLAKE2b-256 checksum
How to use checksums
61efcc200f84da0c8a9050a26eb495a60199742ea2554fe89f55ce29f7521480
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Security for subagent-mail 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for subagent_mail-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page