marketing

Newsletter signup (Brevo/Mailchimp)

Form iscrizione newsletter con double opt-in via mail di conferma, sync automatica verso lista Brevo (ex Sendinblue) o Mailchimp con tag/segmenti, gestione unsubscribe one-click conforme RFC 8058 e GDPR.

Cosa fa questo modulo

Modulo «Newsletter signup (Brevo/Mailchimp)»: blocco riusabile per acquisizione iscritti newsletter pensato per essere embeddato in footer sito, popup exit-intent, sezione hero landing, sticky sidebar blog, fine articolo CMS, modal CTA post-acquisto checkout (#8319), o card sidebar dashboard area cliente (#8326). Componenti: campo email (single-field per massima conversion mobile, opz. nome+cognome+preferenze segmento per profilazione), checkbox consenso marketing GDPR esplicito separato dalla privacy policy (granulare opt-in per finalità — newsletter prodotti, newsletter offerte, newsletter editoriale), honeypot anti-bot, captcha invisibile Cloudflare Turnstile opt-in via config, validazione email DNS MX server-side (lib `egulias/email-validator`), blacklist domini disposable (mailinator/guerrillamail/yopmail/etc), normalizzazione email lowercase+trim+rimozione plus-addressing opzionale, rate limit per IP (max 5 submission/h/IP) e per email (max 3 tentativi/24h/email per evitare lock account legittimo). Flusso double opt-in (DOI) conforme art.7 GDPR e best practice Brevo/Mailchimp: 1) utente compila form e POST `/newsletter/subscribe`, 2) backend valida + crea record `NewsletterSubscriber` status=`pending` con `confirmation_token` UUID univoco scadenza 7gg, salva consensi + IP + user-agent + source_url + utm_source/medium/campaign per attribuzione, 3) invio mail di conferma (#8331 mail transazionale template branded con CTA grande «Conferma iscrizione», fallback link testuale, footer con motivo ricezione + indirizzo fisico mittente come richiesto CAN-SPAM/GDPR), 4) utente clicca link `/newsletter/confirm/{token}` → backend aggiorna status=`confirmed`, registra `confirmed_at`+`confirmation_ip`, push verso provider esterno (Brevo `POST /v3/contacts` con `listIds`+`attributes`+`updateEnabled=true` oppure Mailchimp `POST /lists/{listId}/members` con `status=subscribed`+`merge_fields`+`tags`+`interests`), 5) atterraggio su landing page «iscrizione confermata, benvenuto!» con eventuale CTA secondaria (segui social, sconto benvenuto, contenuto premium download), 6) eventuale welcome email automatica (sequenza onboarding) lato provider o lato Laravel via #8331. Provider integration layer astratto: interfaccia `NewsletterProviderInterface` con metodi `subscribe(email, attributes, tags)`/`unsubscribe(email)`/`update(email, attributes)`/`getStatus(email)`/`addTags(email, tags)`/`removeTags(email, tags)`/`listLists()`/`createList(name)`, implementazioni `BrevoNewsletterProvider` (riusa `BrevoApiTransport` già presente per mail, stesso `BREVO_API_KEY`, endpoint `api.brevo.com/v3/contacts`+`/v3/contacts/lists`) e `MailchimpNewsletterProvider` (lib `mailchimp/marketing` ufficiale, server prefix da API key `us1`/`us19`/etc, `MAILCHIMP_API_KEY`+`MAILCHIMP_DEFAULT_LIST_ID`/`MAILCHIMP_DC`), driver-based via config `services.newsletter.driver` con switch zero-code tra provider per cliente workspace (Klabhouse usa Brevo, Holiday Self Drive può usare Mailchimp se cliente preferisce, gestionali B2B usano Brevo per costo). Modello dati: tabella `newsletter_subscribers` (id, email univoco indicizzato lowercase, status enum `pending`/`confirmed`/`unsubscribed`/`bounced`/`complained`/`cleaned`, first_name nullable, last_name nullable, locale `it`/`en` per segmentazione lingua, source_url referrer iscrizione, source_widget enum `footer`/`popup`/`exit-intent`/`sticky`/`checkout`/`area-cliente`/`landing-x` per analisi performance widget, utm_source/medium/campaign/term/content per attribuzione marketing, ip_address+user_agent (hash o purge dopo X gg per GDPR), confirmation_token uuid nullable scadenza, confirmation_sent_at, confirmation_resent_count, confirmed_at, confirmation_ip, unsubscribed_at, unsubscribe_reason free-text opz, unsubscribe_token uuid permanente per link one-click, provider_contact_id nullable (id contatto su Brevo/Mailchimp per future sync update), provider_last_sync_at, provider_sync_status enum `pending`/`synced`/`failed`+last_error, tags JSON array (es. `["interessato-corsi","klabhouse","early-adopter"]`), preferences JSON (segmenti opt-in granulari), bounce_count int+bounce_last_at per hard bounce auto-cleanup, complaint_at se segnalato spam, gdpr_consent_marketing_bool+gdpr_consent_marketing_at+gdpr_consent_marketing_ip, gdpr_consent_privacy_bool+gdpr_consent_privacy_at, created_at/updated_at), tabella `newsletter_consent_logs` (audit immutabile id+subscriber_id+event enum `subscribed`/`confirmed`/`unsubscribed`/`bounced`/`complained`/`updated`/`tagged`+payload JSON+ip+user_agent+source+timestamp, append-only per prova legale GDPR e per debug 18 mesi retention), tabella `newsletter_provider_sync_queue` (id, subscriber_id, operation enum subscribe/unsubscribe/update/tag, payload JSON, attempts int, last_error, next_retry_at, completed_at — coda asincrona retry esponenziale per resilienza vs downtime API Brevo/Mailchimp). Endpoint pubblici: `POST /newsletter/subscribe` (form submit, restituisce JSON `{ok:true, message}` o errori validation; throttle middleware `throttle:5,1,ip` Laravel), `GET /newsletter/confirm/{token}` (conferma DOI con redirect a landing «benvenuto»), `GET /newsletter/unsubscribe/{token}` (one-click List-Unsubscribe RFC 8058: GET sufficiente per UX immediata + POST per conformità RFC 8058 List-Unsubscribe=One-Click), `POST /newsletter/unsubscribe/{token}` (con motivo opz), `POST /newsletter/preferences/{token}` (centro preferenze: aggiorna segmenti opt-in granulari senza unsubscribe totale — riduce churn vs unsubscribe definitivo), `POST /webhooks/brevo/events` e `POST /webhooks/mailchimp/events` (webhook inbound per sync stato remoto verso locale: bounce, complaint, unsubscribe avvenuto direttamente su provider lato cliente che riceve mail con link unsub provider-side — devono sincronizzare locale per consistenza). Componente frontend: blade component `<x-newsletter.signup variant="footer|inline|popup|exit-intent|sticky" :tags="[...]" :default-list="..." :source-widget="..." />` con varianti CSS preset (footer compatto single-row, inline blog larghezza piena con copy editoriale, popup centered modal con illustration, exit-intent slide-up bottom-right, sticky sidebar verticale), submit AJAX Livewire o vanilla fetch verso endpoint, gestione stati UI loading/success/error/already-subscribed (UX «sei già iscritto, controlla la casella per eventuale conferma pendente»), reset form post-success con messaggio non-intrusivo. Integrazione widgets: popup exit-intent con cookie suppression 14gg post-close per non spammare (mouseleave verso top trigger desktop, scroll-50%+5s mobile equivalent), sticky scroll-triggered (mostra dopo 60% scroll articolo blog), checkout post-purchase auto-opt-in con checkbox pre-flagged solo se compliance EU permette (default unflagged per IT/EU, opzionale flagged per mercati con soft opt-in legittimo dopo acquisto art.130 D.lgs.196/2003 «interesse legittimo» — sicuro per email transazionali correlate prodotto stesso, dubbio per generale → consigliato sempre unflagged), area cliente sezione «Preferenze comunicazioni» con toggle iscritto/non iscritto + multi-checkbox segmenti (#8326 area cliente). Sync provider con coda Laravel: ogni transizione status (subscribe→pending, confirm→confirmed, unsubscribe) dispatch job `SyncNewsletterContactJob` su coda `newsletter` (Redis/database driver), job chiama provider API con retry esponenziale 5 tentativi (1min/5min/30min/2h/12h), failure permanente flagga `provider_sync_status=failed`+`last_error` per riconciliazione manuale admin. Resilienza: se Brevo/Mailchimp down al momento iscrizione, locale è source of truth (subscriber sempre creato), sync differita al ritorno servizio, no double-write impossibile (idempotenza via `provider_contact_id` cache + `updateEnabled=true` Brevo che fa upsert su email). Webhook inbound bidirezionale: Brevo webhook eventi `unsubscribe`/`hard_bounce`/`spam`/`blocked` aggiorna locale subscriber, Mailchimp webhook `unsubscribe`/`cleaned`/`profile`/`upemail` (email change) sync stato + email canonica aggiornata. Admin CRUD: datatable Livewire #8327 subscribers con filtri (status, tags, lingua, source_widget, range date, range bounce_count, provider_sync_status), bulk actions (export #8328 CSV/Excel/PDF, tag add/remove batch, unsubscribe forzato GDPR, push re-sync provider, send test email a sample), dettaglio subscriber con timeline `newsletter_consent_logs` per debug consenso (quando si è iscritto, da quale source, IP, eventuale cambio preferenze, unsubscribe se avvenuto e perché, sync provider success/fail timeline), CRUD `newsletter_lists` interne (mapping verso liste provider remote: lista «Footility news» local id=1 ↔ Brevo listId=12, automatic sync con Brevo lista master), CRUD segmenti/tag suggeriti per dropdown form (no free-text per evitare proliferazione tag con typo), dashboard analytics widget aggregati (totale confirmed, nuovi ultimi 30gg, growth rate %, churn rate unsubscribe %, top source widget per conversion, bounce rate health). Compliance GDPR: doppio consenso esplicito obbligatorio (privacy policy distinto da marketing newsletter), audit log immutabile con IP+timestamp+source+versione testo consenso mostrato all utente, diritto oblio via `POST /newsletter/forget/{token}` con email-verified (hard delete subscriber + anonimizzazione log mantenendo solo hash email + flag per impedire re-iscrizione fraudolenta in nome utente), diritto accesso `GET /newsletter/my-data/{token}` ritorna JSON tutti dati raccolti, retention configurabile (pending non confermati purge dopo 30gg con cron `php artisan newsletter:purge-unconfirmed`, unsubscribed soft-delete mantenuto 24 mesi per evidenza opt-out poi hard delete con `newsletter:purge-unsubscribed --older-than-days=730`). Compliance CAN-SPAM/Yahoo-Google 2024 sender requirements: List-Unsubscribe header sia mailto sia HTTPS one-click in ogni mail outbound (lato provider auto-injected), DMARC/SPF/DKIM allineati su dominio mittente (config Brevo SMTP autenticato), tasso complaint <0.3% monitorato dashboard (auto-pause campagne se supera), bounce rate <2% con auto-cleanup hard bounce, footer mail con indirizzo fisico mittente + motivo ricezione + link gestione preferenze visibile. Compliance Italia (Garante Privacy): consenso libero+specifico+informato+inequivocabile+documentabile (audit log soddisfa), no soft opt-in B2C salvo email transazionali post-acquisto stesso prodotto categoria (default UI conservativa unflagged), titolare trattamento + DPO contact + base giuridica art.6.1.a (consenso) chiariti in informativa linkata. Anti-abuse e quality: limite per IP e per email, validazione email reale tramite double opt-in (no fake email accettata in lista finale), rilevamento role-based email (info@, admin@, noreply@) con warning UX «consigliamo email personale per ricevere comunicazioni dedicate» (opt-in comunque permesso), blacklist domini concorrenti opz. (uso B2B per pulire lista da scraping concorrenza), Levenshtein distance suggestion per typo email comune (`gmial.com`→`gmail.com`, `hotnail.com`→`hotmail.com`, prompt «forse intendevi {x}?»). Performance: idempotenza endpoint subscribe (POST stesso email pending non duplica, re-invia mail conferma dopo cooldown 1h e incrementa `confirmation_resent_count`), coda async sync provider non blocca UX submit, cache config provider+listId+default tags, prefetch widget assets (CSS critical inline, JS deferred). Comandi artisan: `php artisan newsletter:sync-pending` (re-tenta sync provider falliti), `php artisan newsletter:purge-unconfirmed --older-than-days=30`, `php artisan newsletter:purge-unsubscribed --older-than-days=730`, `php artisan newsletter:reconcile-provider` (full sync locale↔provider per ricostruire stato consistente dopo incidente — diff bidirezionale e merge rules: locale unsubscribed prevale su provider subscribed, provider bounced/complained prevale su locale), `php artisan newsletter:export {--status=} {--format=csv|xlsx}`, `php artisan newsletter:report-growth {--month=}` (report mensile crescita+churn+source attribution+conversion widget per stakeholder), `php artisan newsletter:detect-suspicious` (segnala pattern anomali: spike iscrizioni da stesso IP, domini disposable sfuggiti a blacklist, sequenze sequenziali tipo bot `a1@`/`a2@`/`a3@`), `php artisan newsletter:resend-confirmation {email}` (manuale per supporto cliente che non riceve DOI mail). Casi d uso workspace: Footility (footer footility.com sezione «Resta aggiornato sulle novità del workspace», popup post-prima-attività agentic creata «vuoi sapere quando aggiungiamo nuovi moduli?», area cliente sezione preferenze comunicazione), Klabhouse (footer + popup landing corsi specifici con tag corso per segmento — «Sono iscritto per news matematica» — già presente vista NewsletterController e footer-front.blade.php in repository deployata, sync Brevo lista master + tag corso), Holiday Self Drive (footer sito booking + checkout post-prenotazione opt-in «ricevi offerte stagionali viaggi» con segmento per destinazione preferita, Brevo o Mailchimp a scelta cliente), gestionali B2B Casarile/Altramusica/LB advisory (newsletter editoriale tecnica con tag categoria gestionale per nurturing lead pre-vendita), the-body-code/realpilates (newsletter contenuti benessere mensile con segmento per livello fitness e obiettivo, integrato con #8326 area cliente preferenze comunicazione + #8331 mail transazionali sequenza welcome), mscarichi (newsletter offerte stagionali servizi sgomberi+traslochi, tag B2B vs B2C per copy diverso), prontointervento (newsletter consigli manutenzione preventiva post-intervento, opt-in checkout fattura — incentivo a richiamare per prossimi interventi). Estensioni roadmap: A/B test copy form (titolo+sotto+CTA+illustration) con sistema split traffic e metriche conversion per variante, AI personalizzazione subject welcome email per segmento (#8331+LLM genera copy custom da profilo subscriber), preference center avanzato con frequency cap utente-side (es. «massimo 1 mail/settimana» self-service), magic link login passwordless per area cliente (#8326) sfruttando stesso token unsubscribe pattern, social proof («15.234 iscritti» live counter sotto form per riprova sociale, fetch cached aggregato), referral program («invita amico, sblocca contenuto premium») con tracking inviti tabella `newsletter_referrals`, integrazione CDP esterna (Segment.com, Customer.io, Klaviyo come alternative provider futuro), import bulk da CSV/Excel con dedupe+validazione+consenso check per migrazione da fornitori legacy, esportazione segmento dinamico verso ads platform (Meta Custom Audience, Google Customer Match) tramite hash email — ATTENZIONE GDPR: solo con consenso esplicito specifico ads, audit logged. Differenze e relazioni con altri moduli: **#8316 lead-capture-multi-step** è form qualificazione lead complesso multi-step → questo è single-email signup ottimizzato per low-friction high-volume newsletter (no conflict, complementari: lead-capture finale offre opt-in newsletter); **#8331 mail transazionali con template** è il mailer che esegue invio mail DOI+welcome+broadcast — dipendenza diretta; **#8326 area cliente** ospita preference center per gestione opt-in granulari self-service; **#8330 audit log azioni utente** può accogliere `newsletter_consent_logs` come categoria audit dedicata; **#8327 datatable Livewire** per CRUD subscribers admin; **#8328 export Excel/PDF** per export liste/segmenti; **#8104 form-contatti-lead** form contatti generico — diverso da newsletter signup che è opt-in marketing puro (no aspettativa risposta umana 1:1); **#8319 checkout Stripe one-shot** può integrare checkbox opt-in newsletter post-acquisto. Codice esistente da riusare/adattare: Klabhouse repo deployata ha già `NewsletterController` + `BrevoApiTransport` + sezioni footer `footer-front.blade.php` con form newsletter — il modulo Footility-wide astrae quel pattern in package riusabile workspace-wide con provider abstraction + double opt-in + audit GDPR strutturato (Klabhouse legacy usa single opt-in semplificato senza conferma mail e senza centro preferenze formale, da upgrade-are per compliance 2026). Costo implementazione (modulo nuovo, non già presente strutturato su Footility.com): 0.5 giorno migrazioni `newsletter_subscribers`+`newsletter_consent_logs`+`newsletter_provider_sync_queue`+`newsletter_lists`, 1 giorno `NewsletterService` business logic (subscribe/confirm/unsubscribe/forget) + state machine status + token DOI/unsubscribe + audit log automatico, 1 giorno provider abstraction `NewsletterProviderInterface` + `BrevoNewsletterProvider` (riuso `BrevoApiTransport` per HTTP client autenticato) + `MailchimpNewsletterProvider` con lib ufficiale + factory driver-based via config, 0.5 giorno endpoint pubblici (`subscribe`/`confirm`/`unsubscribe`/`preferences`/`forget`) + throttling + validation rules + landing pages confermata/già-iscritto/error/preferences/goodbye, 0.5 giorno componente blade `<x-newsletter.signup>` con varianti footer/inline/popup/exit-intent/sticky + AJAX Livewire submit + UX stati loading/success/error/already-subscribed, 0.5 giorno mail DOI #8331 template branded + welcome email + sequenza onboarding opzionale + List-Unsubscribe header config invio, 0.5 giorno job `SyncNewsletterContactJob` async con retry + coda dedicata `newsletter` + monitoring failure provider_sync_status=failed dashboard, 0.5 giorno webhook inbound `/webhooks/brevo/events`+`/webhooks/mailchimp/events` con verifica firma HMAC + sync bidirezionale stato bounce/complaint/unsubscribe lato provider, 0.5 giorno admin CRUD datatable #8327 + dettaglio timeline consent logs + bulk actions + export #8328 + dashboard analytics widget (growth/churn/source/health), 0.5 giorno comandi artisan (sync-pending/purge-unconfirmed/purge-unsubscribed/reconcile-provider/report-growth/detect-suspicious/resend-confirmation), 0.5 giorno compliance GDPR (audit log immutabile + diritto oblio endpoint + retention configurabile + soft opt-in disabilitato by default), 0.5 giorno integrazioni widget cross-modulo (#8319 checkbox checkout / #8326 preference center area cliente / #8316 lead-capture step finale opt-in), 0.5 giorno testing flussi (subscribe pending→DOI confirm→sync Brevo verified su account test, unsubscribe one-click + sync provider, bounce webhook update locale, GDPR forget hard delete + log anonimizzato, retry job se Brevo 503, edge case email già confirmed re-submit, typo email Levenshtein suggestion, rate limit per IP+email, captcha anti-bot, double-submit idempotenza). Costo riuso per nuovo cliente workspace (modulo pronto): 0.25g config API key Brevo/Mailchimp cliente + creazione lista master + scelta provider, 0.25g personalizzazione copy mail DOI/welcome/footer + branding logo+colori cliente, 0.25g embed widget in footer/landing/area-cliente sito cliente con varianti scelte, 0.25g test E2E DOI verified end-to-end + verify sync provider, 0.5g opz custom segmenti/tag cliente + import CSV legacy lista esistente + dedupe+validazione+consenso check. Dipendenze: Laravel 10/11+ con Livewire 3 per componente reattivo widget, mailer #8331 per invio DOI/welcome (Brevo SMTP o Mailgun o SES via `BrevoApiTransport`), coda Redis/database per `SyncNewsletterContactJob` retry async, lib `mailchimp/marketing` ufficiale se driver Mailchimp, riuso `BrevoApiTransport` esistente se driver Brevo, opz. Cloudflare Turnstile/hCaptcha per captcha invisibile, lib `egulias/email-validator` per DNS MX check, opz. #8326 area cliente per preference center self-service, opz. #8327 datatable Livewire per admin CRUD subscribers, opz. #8328 export Excel/PDF per liste/segmenti, opz. #8330 audit log unificato per consent_logs, opz. #8316 lead-capture-multi-step come pre-step qualificazione che termina con opt-in newsletter, opz. #8319 checkout Stripe per opt-in post-acquisto checkbox, opz. #8331 mailer transazionale per sequenza welcome onboarding.

Esempi d'uso

  • marketing

Disponibile nei pacchetti