Référence de l’API de formulaire

Détails techniques pour connecter un formulaire à MailContact.

Vous utilisez un créateur de site ? Commencez par Ajouter un formulaire de contact pour les étapes et un prompt à copier.

Copiez le lien de formulaire depuis les paramètres du projet. Il ressemble à ceci, avec l’identifiant de votre formulaire à la fin :

votre lien de formulaire
POST https://mailcontact.app/api/forms/your-form-id

Il accepte à la fois FormData (ce qu’envoie un formulaire HTML natif) et application/json. Les envois acceptés arrivent dans votre boîte de réception et déclenchent vos canaux de notification. Les messages placés dans les spams attendent un examen sans notification ni consommation du quota.

Champs

champrequirednotes
namefacultatifAffiché comme expéditeur. Utilise l’email si vide. 200 caractères maximum.
emailrequiredL’email de l’expéditeur. Les adresses invalides ou absentes sont refusées avec un statut 400.
subjectfacultatif300 caractères maximum.
messagerequiredLe corps du message. Non vide, 5 000 caractères maximum.

Un champ texte obligatoire nommé company_website doit être présent et vide. Une valeur non vide identifie un envoi automatisé, ignoré silencieusement (c’est le l’astuce antispam du champ piège). Tous les autres champs inconnus sont ignorés.

Le script injecte ce champ pour les formulaires marqués. Un champ absent déclenche FORM_CHECK_MISSING; un champ rempli est ignoré silencieusement. Un champ vide ne contourne jamais les autres contrôles antispam, de débit ou de vérification. Un robot plus avancé peut toujours reconnaître ce piège.

Le client hébergé ignore silencieusement un piège rempli avant toute requête de configuration ou d’envoi. Il se résout avec { ok: true } pour garder la confirmation normale, comme la réponse antirobot du point de réception. Les appels directs à l’API gardent le même piège serveur.

Recommandé : utilisez le script MailContact

Ajouter data-mailcontact-form au formulaire et chargez notre script une fois par page. Gardez vos styles. Le script gère l’envoi, les retours accessibles sur place, la vérification et les nouvelles tentatives. Il conserve le texte en cas d’erreur et réinitialise seulement après succès confirmé.

Le gestionnaire automatique bloque les nouveaux envois pendant la requête et 10 secondes après un succès confirmé. Boutons et envois clavier restent désactivés pendant ce délai. Les champs redeviennent modifiables et la confirmation reste visible. Les erreurs autorisent un nouvel essai immédiat, sauf si le serveur fournit un Retry-After délai.

contact.html
<form action="https://mailcontact.app/api/forms/your-form-id" method="POST" data-mailcontact-form>
  <label>Email <input type="email" name="email" maxlength="320" required /></label>
  <label>Message <textarea name="message" maxlength="5000" required></textarea></label>
  <button type="submit">Send</button>
  <p data-contact-status role="status" aria-live="polite" aria-atomic="true"></p>
</form>
<script defer src="https://mailcontact.app/forms/v1.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Un seul script prend en charge plusieurs formulaires, y compris ajoutés plus tard. Il injecte le contrôle caché une fois à l’initialisation puis vérifie sa présence et sa valeur vide à l’envoi. Un champ retiré ou désactivé bloque l’envoi et conserve le brouillon. Il envoie vers le action, quel que soit l’hébergement du script. Utilisez HTTPS (ou localhost) pour la vérification automatique. Le générateur propose aussi un noscript solution de repli ; pour une intégration manuelle sans JavaScript, utilisez l’exemple HTML simple ci-dessous.

Vous contrôlez HTML, CSS, libellés et bouton. Seuls les noms des champs pris en charge doivent rester identiques ; les autres sont ignorés. Définissez data-mailcontact-success="Thanks, we’ll reply soon." sur le formulaire pour personnaliser la confirmation. Pour un parcours entièrement personnalisé, utilisez MailContact.send() ci-dessous.

Langue des messages de retour

Les messages d’envoi, de vérification, de confirmation et d’erreur suivent les préférences du navigateur. Français, anglais, espagnol, allemand, italien et portugais sont pris en charge, dont les variantes régionales comme fr-CA et pt-BR. La première langue prise en charge dans les préférences du navigateur est utilisée ; à défaut, les messages de retour s’affichent en anglais.

Définissez data-mailcontact-language="fr" sur un formulaire automatique pour imposer le français, indépendamment du navigateur et des autres formulaires. Une langue forcée prise en charge est prioritaire ; une valeur vide ou inconnue utilise le navigateur. Ce réglage est lu à chaque envoi. Les libellés, le contenu original du bouton et data-mailcontact-success restent sous votre contrôle ; les confirmations personnalisées ne sont jamais traduites automatiquement. Les bulles de validation natives restent gérées par le navigateur.

Imposer les messages de retour en français
<form action="https://mailcontact.app/api/forms/your-form-id" method="POST"
  data-mailcontact-form data-mailcontact-language="fr">
  <!-- Keep your existing fields, button and status element here. -->
</form>

Les formulaires d’un compte Free affichent un petit lien « Traité par mailcontact.app ». Ceux de Pro et Plus n’ont pas d’attribution MailContact. Le script lit ce réglage depuis l’offre du propriétaire : il se met à jour après un changement d’offre sans remplacer l’intégration. Le réglage peut être mis en cache pendant une minute. Appliquez vos styles au data-mailcontact-branding élément pour l’adapter à votre site.

Si votre site définit une Content Security Policy, autorisez l’origine du script dans script-src et l’origine du point de réception du formulaire dans connect-src et form-action. Aucune autorisation JavaScript en ligne n’est nécessaire pour cette intégration. Le v1 l’URL reçoit les mises à jour compatibles ; une rupture d’intégration future utilisera une nouvelle version. Vous pouvez écouter l’événement propagé mailcontact:success événement pour ajouter votre propre comportement après succès.

Interfaces entièrement personnalisées

Chargez le même script, puis appelez MailContact.send() depuis votre gestionnaire. Omettez data-mailcontact-form pour que le gestionnaire automatique laisse votre interface intacte. Vous contrôlez étapes, chargement, erreurs et confirmation ; la fonction gère la requête, la vérification signée et le nouvel envoi. Elle ne modifie jamais le DOM et ne vide pas les champs.

custom-form.js — à exécuter après le chargement du script
const endpoint = "https://mailcontact.app/api/forms/your-form-id";
const form = document.querySelector("#contact-form");
MailContact.prepare(form); // Inject once before the visitor fills the form.
const language = form.getAttribute("data-mailcontact-language") || undefined;
const text = MailContact.getMessages(language);
const config = await MailContact.getConfig({ endpoint, language });
// If config.branding is true, show a visible "Processed by mailcontact.app"
// link to https://mailcontact.app in your own form layout.

async function submit() {
  showStatus(text.sending);
  try {
    await MailContact.send({
      endpoint,
      data: new FormData(form),
      language, // Optional: omit for automatic browser language detection.
      onVerification: () => showStatus(text.verification),
      brandingElement: document.querySelector("[data-mailcontact-branding]"),
      // signal: abortController.signal, // optional cancellation
    });
    showYourConfirmation();
  } catch (error) {
    // error.code, error.status and error.retryAfter (seconds or null)
    // let you choose your own translated feedback. Keep the draft.
    showYourError(error);
  }
}

MailContact.prepare(form) ajoute seulement le champ caché ; il ne connecte pas de gestionnaire d’envoi ni ne modifie le design. Appelez-le une fois sur chaque formulaire monté avant interaction. Il ne recrée jamais un champ supprimé ni ne vide une valeur existante. data accepte aussi un objet contenant name, email, subject, message et le champ requis company_website valeur. Le client conserve une copie des champs pour retenter la vérification. Il confirme la réception ou ignore silencieusement un piège rempli avec { ok: true }, et lève MailContact.FormError pour les échecs. Les contrôles absents utilisent FORM_CHECK_MISSING, les erreurs réseau utilisent NETWORK_ERROR, une annulation ou un dépassement du délai utilise ABORTED. Le délai est de 60 secondes, avec au maximum une nouvelle tentative de vérification.

MailContact.getConfig({ endpoint }) effectue un GET public sur l’URL du formulaire et renvoie uniquement { branding: true | false }. Les interfaces personnalisées affichent elles-mêmes cette mention lorsqu’elle est requise et transmettent son élément comme brandingElement (ou une fonction qui le renvoie). Chaque envoi vérifie le paramètre du serveur. Avec Free, un lien absent, masqué, illisible ou non cliquable vers https://mailcontact.app déclenche BRANDING_REQUIRED avant tout envoi ; Pro et Plus n’ont pas besoin de lien. Ce contrôle d’intégration s’effectue dans le navigateur et ne prouve pas au serveur le contenu d’une page tierce. Il ne révèle ni l’identité du propriétaire ni ses informations de facturation. React, Vue et les autres frameworks peuvent appeler ces fonctions après le chargement du script ; l’API brute reste aussi disponible.

Le client personnalisé traduit FormError.message automatiquement ; code, status et retryAfter restent inchangés. Transmettez language: "fr" vers send() ou getConfig() pour remplacer la langue du navigateur. Un gestionnaire personnalisé lit lui-même l’attribut du formulaire, comme ci-dessus. MailContact.getMessages(language?) renvoie le texte de retour adapté à votre interface, notamment sendingButton, sending, verification, success et wait(seconds). Il renvoie un objet distinct afin que votre texte personnalisé ne modifie pas les autres formulaires. Une preuve automatique en échec utilise VERIFICATION_FAILED. Aucun service de traduction ni requête de langue supplémentaire n’est utilisé ; les réponses JSON brutes de l’API conservent leurs codes et leur langue actuels.

Vérification automatique des envois suspects

Le script hébergé gère la vérification. Les clients personnalisés peuvent envoyer _verification: "1" pour prendre en charge la vérification automatique. Une requête suspecte peut renvoyer HTTP 403 avec code: CHALLENGE_REQUIRED et un signé challenge objet. Aucun message livré ni consommation du quota. Résolvez le défi et renvoyez les champs d’origine avec la solution JSON dans _proof. Le script autonome /form-challenge.js la fonction expose window.mailcontactSolveChallenge(challenge, signal?), qui renvoie cette chaîne JSON. Les requêtes personnalisées suspectes contenant le contrôle requis, mais sans prise en charge de la vérification, sont placées dans les spams pour examen ; l’absence de vérification ne contourne jamais le contrôle.

La preuve expire après cinq minutes, est liée aux champs exacts, au formulaire et au client, et n’est acceptée qu’une fois. Gardez le brouillon si la vérification échoue. Les formulaires natifs reçoivent une page de vérification automatique. Les messages très suspects sont reçus dans les spams, sans notification ni quota ; la réponse publique ne révèle pas ce classement.

Formulaire HTML simple

La version sans JavaScript. Nommez les champs comme ci-dessus et le navigateur fait le reste :

contact.html
<form action="https://mailcontact.app/api/forms/your-form-id" method="POST">
  <input type="text" name="name" placeholder="Your name" />
  <input type="email" name="email" placeholder="[email protected]" required />
  <input type="text" name="subject" placeholder="Subject" />
  <textarea name="message" placeholder="Your message" required></textarea>
  <button type="submit">Send</button>
  <input name="company_website" type="text" tabindex="-1" autocomplete="off"
    style="position:absolute;left:-10000px" aria-hidden="true" />
</form>

Un envoi natif de formulaire ouvre la réponse JSON du point de réception en cas de succès, ou une page HTML de vérification si nécessaire. Utilisez notre script ci-dessus pour garder les visiteurs sur la page et afficher la confirmation sur place.

JSON avec fetch

Envoyer application/json avec un Content-Type en-tête. Mêmes champs, même validation :

submit.js
const res = await fetch("https://mailcontact.app/api/forms/your-form-id", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    name: "Ada",
    company_website: "",
    email: "[email protected]",
    subject: "Hello",
    message: "Trying out the endpoint.",
  }),
});

const data = await res.json();
if (data.ok) {
  // show your inline "thanks, message sent" state
}

Vous pouvez aussi envoyer un POST FormData objet depuis JavaScript : omettez le Content-Type en-tête et transmettez new FormData(formElement) comme corps.

CORS

CORS est ouvert : le point de réception répond avec Access-Control-Allow-Origin: * et gère le OPTIONS prérequête : les envois fonctionnent depuis toute origine, domaine, localhost, préproduction ou hébergeur statique comme GitHub Pages. Aucune liste d’autorisation à gérer.

Réponses et erreurs

En cas de succès, le point de réception renvoie 200 avec {"ok": true}. Cela couvre aussi les messages placés dans les spams et les contrôles remplis ignorés silencieusement ; cela ne garantit pas une livraison dans la boîte principale. Les erreurs de validation sont au format JSON : {"ok": false, "code": "...", "error": "..."}. La vérification utilise {"ok": false, "code": "CHALLENGE_REQUIRED", "challenge": {...}}, ou une page HTML pour les envois natifs du navigateur. Un JSON mal formé, des types de champs incorrects, des champs en double ou trop longs renvoient 400 :

statuterrorlorsque
403Vérification automatique requise.CHALLENGE_REQUIRED: résolvez le défi signé et renvoyez les champs d’origine avec _proof. Une preuve invalide, expirée ou réutilisée reçoit un nouveau défi. Le script hébergé effectue automatiquement une nouvelle tentative.
400Contrôle du formulaire absent.FORM_CHECK_MISSING: le company_website champ est absent. Le script l’injecte à l’initialisation ; les intégrations natives et API brutes doivent l’inclure explicitement.
400Une adresse email valide est requise.email est absent, invalide ou dépasse 320 caractères
400Le message ne peut pas être vide.message est absent ou vide
404Formulaire inconnu.l’identifiant de formulaire dans l’URL n’existe pas
413Requête trop volumineuse.corps de requête supérieur à 64 Ko
429Trop de requêtes.plus de 20 requêtes de formulaire par minute depuis une IP, ou 60 messages acceptés par minute dans une boîte
429Trop de requêtes.Plus de 5 envois acceptés par minute depuis le même email vers un formulaire, même avec des IP différentes. Un Retry-After l’en-tête indique le délai d’attente.
429Ce message a déjà été reçu.Le même expéditeur, objet et message ont déjà été acceptés par ce formulaire dans la dernière minute. Le code de réponse est DUPLICATE_MESSAGE. Aucun message, notification ou consommation du quota supplémentaire n’est créé.
429Quota mensuel atteint.Le code de réponse est MONTHLY_QUOTA_EXCEEDED, avec un Retry-After en-tête jusqu’au prochain renouvellement mensuel du quota du compte.
429La boîte ne peut plus recevoir de messages à examiner.SPAM_STORAGE_LIMIT: le projet contient déjà 500 spams en attente. Aucun message supplémentaire n’est reçu. Utilisez un autre moyen de contact ; la réponse inclut Retry-After.
415Type de contenu non pris en charge.Utilisez JSON, données encodées en URL ou multipart.

Limites

  • Le corps des requêtes est limité à 64 Ko.
  • Limite : 20 requêtes par minute et par IP, conservée après redémarrage ; au-delà, réponse 429 avec Retry-After.
  • Limite expéditeur : 5 envois acceptés par minute, formulaire et email. Les envois identiques sont limités à un par minute ; les variantes d’espaces sont normalisées.
  • Longueur des champs : name 200, subject 300, message 5 000 caractères (les valeurs plus longues sont refusées) ; les emails de plus de 320 caractères sont refusés.

Free inclut 50 envois par mois pour un projet. Pro inclut 1 000 messages partagés entre dix projets ; Plus, 10 000 entre cinquante projets. Messages reçus et réponses consomment le même quota. Les quotas mensuels sont partagés sur le compte ; voir tarifs.

Voir aussi

Nouveau ici ? Commencez par Bien démarrer. Avec Pro et Plus, ajoutez une adresse email de contact alimentant la même boîte. Le Protection antispam explique comment bloquer les messages indésirables sur un point de réception public. Pour un exemple prêt à utiliser, essayez le générateur de formulaire de contact ou le guides de frameworks.