FrameworksAgents.com Logo

Créer un agent marketing IA : tutoriel complet

Tutorielcalendar_todayPublié le 20 avril 2026schedule14 min de lectureagent marketing automatisationagent ia contenu

Construisez un agent marketing IA avec Python : génération de contenu, campagnes email et reporting automatique. Tutoriel pas à pas avec code inclus.

Introduction

Le marketing digital repose sur des tâches répétitives : rédiger des posts, envoyer des emailings, compiler des rapports de performance. Ces opérations consomment des heures chaque semaine — heures que vous pourriez investir dans la stratégie.

Un agent marketing IA les automatise. Branché sur vos APIs (OpenAI ou Anthropic pour la génération de texte, SendGrid ou Mailchimp pour l'envoi, Google Analytics pour les métriques), il exécute un workflow complet de manière autonome : génération, validation optionnelle, envoi, reporting.

Dans ce tutoriel, vous allez construire cet agent de A à Z en Python. Prérequis : un niveau intermédiaire en Python, un compte OpenAI ou Anthropic, et une API d'envoi d'email transactionnel. Durée estimée : 45 minutes. Pour les fondations d'architecture agent (boucle de décision, mémoire, registre de tools), commencez par le guide complet pour créer un agent IA.

Cas d'usage concrets

Un agent marketing couvre trois familles de tâches, déclenchables indépendamment ou en chaîne :

  • Contenu social — variations de posts LinkedIn, X et Instagram à partir d'un même sujet, déclinaisons A/B, calendrier de publication.
  • Email — séquences de bienvenue, newsletters, relances panier, segmentation et personnalisation par contact.
  • Publicité (ads) — génération de jeux d'annonces Google Ads ou Meta (titres, descriptions, accroches), variations par audience à tester.

Le même socle technique sert les trois : un module de génération piloté par un prompt de marque, une couche d'envoi/diffusion, et une couche de mesure. Pour une vue orientée gains mesurables, voir aussi automatiser le marketing avec des agents IA.

Résumé rapide

ÉtapeModuleOutil principal
1Génération de contenuOpenAI / Anthropic
2Campagne emailSendGrid / Mailchimp
3Reporting automatiqueGoogle Analytics API
4OrchestrationPython + schedule

Architecture de l'agent marketing

Avant de coder, le schéma. L'agent marketing suit un pipeline en 4 modules :

Input (brief campagne)
    │
    ▼
[Module 1] Génération contenu
    │  → posts réseaux, variations A/B
    ▼
[Module 2] Campagne email
    │  → segmentation, perso, envoi
    ▼
[Module 3] Reporting
    │  → collecte métriques, résumé LLM
    ▼
Output (rapport exécutif)

Chaque module est indépendant : vous pouvez n'en activer qu'un seul ou chaîner les quatre. Le déclencheur peut être un schedule (quotidien, hebdo) ou un événement externe (nouveau produit, publication d'un article).

Module 1 : génération de contenu

Le premier module utilise un LLM pour produire des variations de contenu marketing. On commence par installer les dépendances :

pip install openai python-dotenv schedule

Configuration de base :

import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

BRAND_VOICE = """Tu es un copywriter expert en marketing digital francophone.
Ton style : direct, persuasif, concret. Pas de formule creuse.
Chaque phrase apporte une information ou un argument."""

def generate_post(topic: str, platform: str, n_variations: int = 3) -> list[str]:
    """Génère N variations de posts pour une plateforme donnée."""
    platform_hints = {
        "linkedin": "350-400 caractères, ton professionnel, inclut un appel à l'action",
        "twitter": "200-280 caractères, ton percutant, un hashtag pertinent",
        "instagram": "150-200 mots, ton engageant, 3-5 emojis maximum",
    }
    prompt = f"""{BRAND_VOICE}

Sujet : {topic}
Plateforme : {platform}
Contraintes : {platform_hints.get(platform, "")}

Génère exactement {n_variations} variations distinctes, numérotées 1 à {n_variations}.
"""
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "system", "content": prompt}],
        temperature=0.8,
    )
    text = response.choices[0].message.content
    return [v.strip() for v in text.split("\n") if v.strip() and v[0].isdigit()]

Exemple d'utilisation :

posts = generate_post(
    topic="Nouvelle fonctionnalité : analyse de performance en temps réel",
    platform="linkedin",
    n_variations=3,
)
for i, post in enumerate(posts, 1):
    print(f"Variation {i}:\n{post}\n")

La variable BRAND_VOICE est votre prompt système. Modifiez-la pour refléter le ton de votre marque. Plus elle est précise, plus les variations seront cohérentes entre elles.

Pour une campagne A/B, générez 2 variations avec des angles différents :

def ab_variations(topic: str) -> tuple[str, str]:
    """Génère 2 variations A/B avec angles distincts."""
    prompt_a = f"""{BRAND_VOICE}\nSujet : {topic}\nAngle : bénéfice client concret (chiffres, résultats)."""
    prompt_b = f"""{BRAND_VOICE}\nSujet : {topic}\nAngle : problème résolu (douleur client avant/après)."""
    
    response_a = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "system", "content": prompt_a}],
    )
    response_b = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "system", "content": prompt_b}],
    )
    return (
        response_a.choices[0].message.content.strip(),
        response_b.choices[0].message.content.strip(),
    )

Générer des annonces publicitaires

La même brique sert à produire des jeux d'annonces (Google Ads, Meta). La différence tient aux contraintes de format imposées par les régies :

def generate_ads(product: str, audience: str, n: int = 3) -> list[dict]:
    """Génère N annonces Google Ads (titres <= 30 car., descriptions <= 90 car.)."""
    prompt = f"""{BRAND_VOICE}

Produit : {product}
Audience cible : {audience}
Contraintes Google Ads : titre <= 30 caractères, description <= 90 caractères.

Génère {n} annonces au format JSON : liste d'objets
{{"titre": "...", "description": "..."}}. Réponds uniquement en JSON valide."""
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"},
        temperature=0.7,
    )
    import json
    return json.loads(response.choices[0].message.content)["annonces"]

Produisez systématiquement plusieurs variantes par audience : c'est la matière première de vos tests A/B côté régie.

Calendrier éditorial automatisé

Plutôt que de générer un post à la fois, l'agent peut planifier un calendrier complet à partir d'une liste de sujets et d'une cadence. La sortie est un fichier exploitable par votre outil de programmation (Buffer, Metricool) ou directement par le scheduler interne :

import csv
from datetime import date, timedelta

def build_calendar(topics: list[str], start: date, cadence_days: int = 2,
                   platform: str = "linkedin") -> list[dict]:
    """Génère un calendrier éditorial : 1 post par sujet, espacé de cadence_days."""
    calendar = []
    for i, topic in enumerate(topics):
        publish_date = start + timedelta(days=i * cadence_days)
        post = generate_post(topic, platform, n_variations=1)[0]
        calendar.append({
            "date": publish_date.isoformat(),
            "platform": platform,
            "topic": topic,
            "content": post,
            "status": "draft",  # jamais "published" sans relecture
        })
    return calendar

def export_calendar(calendar: list[dict], path: str = "calendrier.csv") -> None:
    with open(path, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=calendar[0].keys())
        writer.writeheader()
        writer.writerows(calendar)

Chaque entrée est marquée draft : le calendrier est une proposition, pas une publication. Un humain valide avant la mise en ligne.

Module 2 : campagne email automatisée

L'envoi d'emails marketing impose des contraintes légales (RGPD en Europe). Votre agent respecte le cadre :

  • Double opt-in : l'abonné confirme son inscription par email
  • Lien de désinscription obligatoire dans chaque email (List-Unsubscribe)
  • Pas d'achat de listes : seulement vos propres contacts consentants

Installation SendGrid :

pip install sendgrid
import sendgrid
from sendgrid.helpers.mail import Mail, Email, To, Content

sg = sendgrid.SendGridAPIClient(api_key=os.getenv("SENDGRID_API_KEY"))

def send_campaign(
    subject: str,
    html_body: str,
    recipients: list[dict],
) -> dict:
    """
    Envoie une campagne à une liste de destinataires.
    recipients : [{"email": "x@y.com", "name": "X Y"}, ...]
    RGPD: chaque destinataire doit avoir consenti.
    """
    # Segmentation simple : filtrer les inactifs (exemple)
    active = [r for r in recipients if r.get("active", True)]
    
    # Construction du contenu
    # Note: en production, utilisez un template SendGrid dynamique
    results = {"sent": 0, "failed": 0, "errors": []}
    
    for recipient in active:
        try:
            message = Mail(
                from_email=Email("marketing@votredomaine.com"),
                to_emails=To(recipient["email"]),
                subject=subject,
                html_content=Content("text/html", html_body),
            )
            # Ajout du footer RGPD obligatoire
            message.footer = True
            response = sg.send(message)
            results["sent"] += 1
        except Exception as e:
            results["failed"] += 1
            results["errors"].append({"email": recipient["email"], "error": str(e)})
    
    return results

Pour personnaliser le contenu par segment, utilisez les attributs de contact SendGrid :

def personalize_content(base_html: str, recipient: dict) -> str:
    """Remplace les variables de personnalisation dans le template."""
    replacements = {
        "{{first_name}}": recipient.get("name", "Client").split()[0],
        "{{company}}": recipient.get("company", ""),
        "{{last_purchase}}": recipient.get("last_purchase", "votre dernier achat"),
    }
    content = base_html
    for placeholder, value in replacements.items():
        content = content.replace(placeholder, value)
    return content

Module 3 : reporting de performance

Le troisième module collecte les métriques (via Google Analytics Data API) et utilise le LLM pour produire un résumé exécutif. Pour ajouter des alertes contextuelles, des anomalies et des seuils dynamiques, le complément naturel est Monitoring et data automatisés avec des agents IA :

pip install google-analytics-data
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import RunReportRequest
from openai import OpenAI
import os

GA_PROPERTY_ID = os.getenv("GA_PROPERTY_ID")

# Attention : client GA distinct du client OpenAI utilisé plus bas.
ga_client = BetaAnalyticsDataClient()

def fetch_metrics(days: int = 7) -> dict:
    """Collecte les métriques principales sur N jours via la GA Data API."""
    request = RunReportRequest(
        property=f"properties/{GA_PROPERTY_ID}",
        dimensions=[{"name": "pagePath"}],
        metrics=[
            {"name": "sessions"},
            {"name": "conversions"},
            {"name": "bounceRate"},
        ],
        date_ranges=[{"start_date": f"{days}daysAgo", "end_date": "today"}],
    )
    report = ga_client.run_report(request)
    rows = report.rows or []
    sessions = sum(int(r.metric_values[0].value) for r in rows)
    conversions = sum(int(r.metric_values[1].value) for r in rows)
    bounce = round(
        sum(float(r.metric_values[2].value) for r in rows) / max(len(rows), 1), 2
    )
    top_pages = [r.dimension_values[0].value for r in rows[:5]]
    return {
        "sessions": sessions,
        "conversions": conversions,
        "bounce_rate": bounce,
        "top_pages": top_pages,
    }

def ai_summary(metrics: dict, campaign_name: str) -> str:
    """Génère un résumé exécutif avec le LLM."""
    llm = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
    prompt = f"""Tu es un analyste marketing senior. Voici les métriques d'une campagne
appelée "{campaign_name}" sur les 7 derniers jours :

- Sessions : {metrics['sessions']}
- Conversions : {metrics['conversions']}
- Taux de rebond : {metrics['bounce_rate']}%
- Pages les plus visitées : {', '.join(metrics['top_pages'])}

Rédige un résumé exécutif de 100 mots maximum, en français,
avec 2-3 KPIs mis en avant et une recommandation d'action.
Format : paragraphe unique, pas de listes à puces."""

    response = llm.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
    )
    return response.choices[0].message.content.strip()

Orchestration : enchaîner les 3 modules

Le module d'orchestration déclenche les 3 modules dans l'ordre, avec une validation humaine optionnelle :

import schedule
import time
import threading

class MarketingAgent:
    def __init__(self, config: dict):
        self.config = config
        self.human_validation = config.get("human_validation", True)

    def run_full_campaign(self, campaign_brief: dict):
        """Exécute le pipeline complet campagne."""
        print(f"[1/3] Lancement campagne : {campaign_brief['name']}")

        # Module 1 : contenu
        print("      Generation du contenu...")
        posts = generate_post(
            topic=campaign_brief["topic"],
            platform=campaign_brief.get("platform", "linkedin"),
            n_variations=campaign_brief.get("n_variations", 3),
        )
        print(f"      -> {len(posts)} variations generees")

        # Validation humaine optionnelle
        if self.human_validation:
            print("\n      Validation humaine requise avant envoi.")
            print("      Relisez les contenus ci-dessus.")
            approval = input("      Envoyer ? (o/n) : ")
            if approval.lower() != "o":
                print("      Campagne annulee.")
                return

        # Module 2 : email
        if campaign_brief.get("send_email"):
            print("[2/3] Envoi de la campagne email...")
            results = send_campaign(
                subject=campaign_brief["subject"],
                html_body=self.build_html_email(posts[0]),
                recipients=campaign_brief["recipients"],
            )
            print(f"      -> {results['sent']} emails envoyes, {results['failed']} echecs")

        # Module 3 : reporting
        print("[3/3] Generation du rapport...")
        metrics = fetch_metrics(days=7)
        summary = ai_summary(metrics, campaign_brief["name"])
        print(f"\n      Resume IA :\n      {summary}\n")

    def build_html_email(self, post_content: str) -> str:
        """Construit le HTML de l'email depuis le contenu du post."""
        return f"""
        <html><body>
        <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
            <div style="background: #1a1a2e; color: white; padding: 20px; text-align: center;">
                <h1 style="margin:0;">Votre actualité</h1>
            </div>
            <div style="padding: 20px; line-height: 1.6;">
                <p>{post_content}</p>
                <hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">
                <p style="font-size: 12px; color: #888;">
                    Vous recevez cet email car vous vous êtes inscrit sur notre site.<br/>
                    <a href="#unsubscribe">Se désinscrire</a>
                </p>
            </div>
        </div>
        </body></html>
        """

    def schedule_campaign(self, campaign_brief: dict, time_str: str = "09:00"):
        """Planifie une campagne à une heure donnée (format HH:MM)."""
        schedule.every().day.at(time_str).do(
            self.run_full_campaign, campaign_brief
        )
        print(f"Campagne planifiee chaque jour a {time_str}")


# Lancement
if __name__ == "__main__":
    agent = MarketingAgent(config={"human_validation": True})

    campaign = {
        "name": "Campagne Avril - Feature X",
        "topic": "Nouvelle fonctionnalité : analyse de performance en temps réel",
        "platform": "linkedin",
        "n_variations": 3,
        "subject": "Découvrez notre nouvelle fonctionnalité analytique",
        "send_email": True,
        "recipients": [
            {"email": "client1@example.com", "name": "Jean Dupont", "active": True},
            {"email": "client2@example.com", "name": "Marie Martin", "active": True},
        ],
    }

    # Exécution immédiate (test)
    agent.run_full_campaign(campaign)

    # Ou planifier : agent.schedule_campaign(campaign, "09:00")
    # while True:
    #     schedule.run_pending()
    #     time.sleep(60)

Ce script exécute le pipeline complet en une seule commande. En production, décommentez la section schedule pour un lancement automatique quotidien.

Personnalisation et segmentation

La personnalisation va au-delà du {{first_name}}. La logique gagnante combine segmentation (à qui on parle) et personnalisation (ce qu'on dit). Définissez vos segments par un critère métier — étape du cycle de vie, dernier achat, score d'engagement — puis adaptez à la fois le contenu et le moment d'envoi :

def segment_recipients(contacts: list[dict]) -> dict[str, list[dict]]:
    """Range les contacts dans des segments métier."""
    segments = {"nouveaux": [], "actifs": [], "dormants": []}
    for c in contacts:
        jours = c.get("days_since_last_open", 999)
        if c.get("signup_recent"):
            segments["nouveaux"].append(c)
        elif jours <= 30:
            segments["actifs"].append(c)
        else:
            segments["dormants"].append(c)
    return segments

À chaque segment correspond un angle : message d'onboarding pour les nouveaux, montée en gamme pour les actifs, relance incitative pour les dormants. Le prompt de génération reçoit le segment en variable, ce qui produit un contenu cohérent avec l'intention.

Mesurer le ROI

Un agent marketing se justifie par des chiffres, pas par la nouveauté technique. Trois niveaux de mesure :

Coût évité — comparez le temps humain économisé au coût API. Pour 30 posts et 4 campagnes email par mois, comptez 2 à 6 € d'API contre une dizaine d'heures de production manuelle.

Performance de campagne — taux d'ouverture, taux de clic (CTR), taux de conversion par segment et par variation A/B. C'est ici que la segmentation prouve sa valeur.

ROI net — la formule de référence : ROI = (revenu attribué - coût total) / coût total. Le coût total agrège l'API, les outils d'envoi et le temps de relecture humaine. Attribuez le revenu via des UTM et le suivi de conversion GA4.

Pour automatiser la collecte de ces indicateurs et déclencher des alertes en cas d'anomalie, prolongez le module 3 avec le guide monitoring et data automatisés avec des agents IA.

Tableau récapitulatif des outils utilisés

FonctionOutilAlternative
Génération LLMOpenAI GPT-4oAnthropic Claude
Envoi emailSendGridMailchimp, Brevo
AnalyticsGoogle Analytics Data APIPlausible, Matomo
SchedulingPython scheduleCelery, cron
SegmentationSendGrid contacts APIMailchimp segments

Bonnes pratiques

Révision humaine obligatoire — Ne laissez jamais un agent envoyer des emails sans relecture. Le ton de marque, l'exactitude des données et la conformité RGPD nécessitent un regard humain.

Prompts système stables — Définissez votre BRAND_VOICE une fois et testez-le sur 10 contenus avant de le figer. Un prompt mal calibré produit des variations incohérentes qui nuisent à votre image.

Limites RGPD — En Europe, le consentement doit être explicite et documenté. Conservez une trace du opt-in (date, source). L'agent ne doit jamais envoyer d'email à une personne qui ne s'est pas explicitement inscrite.

Gestion des erreurs — Chaque module retourne ses erreurs séparément. Ne laissez pas un échec en cascade compromettre toute la campagne. Le module email capture les échecs par destinataire et vous permet de retenter uniquement les échecs.

Rate limits — Les APIs (OpenAI, SendGrid) ont des limites de débit. Implémentez un backoff exponentiel :

import time
from openai import RateLimitError

def generate_with_retry(prompt: str, max_retries: int = 3) -> str:
    for attempt in range(max_retries):
        try:
            response = client.chat.completions.create(
                model="gpt-4o",
                messages=[{"role": "user", "content": prompt}],
            )
            return response.choices[0].message.content
        except RateLimitError:
            wait = 2 ** attempt
            print(f"Rate limit — attente {wait}s...")
            time.sleep(wait)
    raise Exception("Max retries exceeded")

Questions fréquentes

Comment maintenir un ton de marque cohérent sur toutes les variations ?

Définissez un prompt système détaillé (brand voice) et générez au minimum 3 variations. Triez par cohérence avec le brand voice avant de valider. Pour les marques avec plusieurs persona (B2B vs B2C), maintenez deux prompts distincts et appliquez le bon selon le segment.

Peut-on utiliser cet agent pour plusieurs clients simultanément ?

Oui. Instanciez un MarketingAgent par client, chacun avec sa propre configuration (API keys, liste de destinataires, brand voice). Attention à bien isoler les données clients et à respecter les quotas d'API par client.

Comment suivre les performances au-delà de Google Analytics ?

Ajoutez des UTMs (Urchin Tracking Module) à chaque lien dans vos emails pour suivre les clics par campagne dans GA4. Pour un tracking plus fin, intégrez des pixels de conversion sur vos pages de destination.

L'agent peut-il gérer des campagnes multilingues ?

Oui. Spécifiez la langue dans le prompt système pour chaque campagne. Pour l'espagnol, l'allemand ou l'italien, GPT-4o fonctionne correctement. Pour des langues moins courantes, privilégiez Claude qui offre une meilleure couverture multilingue.

Comment éviter que les emails finissent en spam ?

Trois leviers : authentification SPF/DKIM/DMARC configurée sur votre domaine d'envoi, taux de désinscription bas (moins de 0,5%), et contenu sans termes spam (évitez "GRATUIT", "GAGNEZ", majuscules excessives). SendGrid fournit un outil de prévisualisation spam avant envoi.

Articles liés

Votre agent marketing est opérationnel. Pour aller plus loin, explorez les automatisations qui s'enchaînent avec ce que l'agent génère :

Restez informé sur les agents IA

Nouveaux tutoriels, comparatifs et guides pratiques directement dans votre boîte mail.

homeAccueilcodeFrameworkssmart_toyAgentsmenu_bookTutorielsTwitter