---
title: "Script PHP per la creazione di liste email double opt-in"
description: "Script in PHP per creare, partendo da un database di email, delle liste di email double opt-in per il marketing via email"
canonical: "https://www.mauriziofonte.it/blog/post/php-creazione-liste-email-double-optin.html"
author: "Maurizio Fonte"
date: "2011-05-09T21:18:20+02:00"
modified: "2011-05-09T21:18:20+02:00"
section: "Database"
tags: ["Database", "SEO"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[Database](https://www.mauriziofonte.it/blog/cat/database.html) [SEO](https://www.mauriziofonte.it/blog/cat/seo.html)

# [Script PHP per la creazione di liste email double opt-in](https://www.mauriziofonte.it/blog/post/php-creazione-liste-email-double-optin.html)

Lunedì 9 Mag 2011, alle 21:18 ![Script PHP per la creazione di liste email double opt-in](https://www.mauriziofonte.it/image/000190200-php-creazione-liste-email-double-optin.jpg)

Se hai un sito qualsiasi, dove richiedi la registrazione per usufruire del sito, molto probabilmente **non hai mai pensato che le email che gli utenti utilizzano per registrarsi possano diventare denaro.**.

L'argomento che andrò a trattare oggi è un pò scottante, lo ammetto: le email di spam, pubblicitarie, sono davvero fastidiose. Ma se abbiamo un sito, e stiamo richiedendo la verifica dell'email dopo la registrazione, **quelle email valgono oro**.

Il problema, però è il seguente: nessun advertiser accetterà mai delle liste di email nelle quali l'utente non abbia **specificatamente dichiarato** di voler ricevere delle email pubblicitarie.

Quindi, come facciamo a **trasformare un semplice e scarno database di contatti email in un vero e proprio database di email DOUBLE OPT-IN?**

Beh, lasciamo fare il lavoro sporco a PHP+mySQL. Per prima cosa, creiamo le tabelle del database per eseguire gli script che faranno funzionare il gioco:

```
CREATE TABLE IF NOT EXISTS `email_marketing_contacts` (
  `id` int(11) NOT NULL auto_increment,
  `email` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `subscribed` tinyint(1) NOT NULL default '0',
  `unsubscribed` tinyint(1) NOT NULL default '0',
  `info_emails` tinyint(1) NOT NULL default '0',
  `double_opt_in` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`),
  KEY `index-emails` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `email_marketing_lists` (
  `id` int(11) NOT NULL auto_increment,
  `email_subject` varchar(255) NOT NULL,
  `email_content_text` longtext NOT NULL,
  `email_content_html` longtext NOT NULL,
  `creation_date` datetime NOT NULL,
  `active` tinyint(1) NOT NULL default '1',
  `completion_date` datetime NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `email_marketing_emailstocrons` (
  `id` int(11) NOT NULL auto_increment,
  `listid` int(11) NOT NULL,
  `contactid` int(11) NOT NULL,
  `email` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `sent` tinyint(1) NOT NULL default '0',
  `sent_date` datetime NOT NULL,
  `status` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;
```

Ovviamente, all'inizio, **tutti i contatti dovranno essere inseriti dentro il database "email_marketing_contacts"**. Sarà vostro compito creare uno script che tenga aggiornato il database dei contatti, senza sovrascritture delle email o compagnia bella.

A questo punto, diamo un'occhiata agli script PHP per creare la nostra bella lista di email double opt-in. Servono:

- Uno script per la creazione di "newsletter" da mandare a tutti i contatti di "email_marketing_contacts"
- Uno script ( magari cronnato ) che invii le email, magari a scaglioni di 100 per volta, per evitare che i servizi di web hosting economici rompano le scatole se inviamo troppe email per volta
- Una pagina cliccabile nell'email che arriverà agli utenti, nella quale l'utente possa scegliere se iscriversi double opt-in oppure disiscriversi completamente

**Codice 1: Creazione delle Email**

```
<?php
if ( isset ( $_POST['email_subject'] ) && strlen ( $_POST['email_subject'] ) > 0 ) {

// CONNESSIONE AL DB - INSERIRE QUI

$sql = "INSERT INTO email_marketing_lists ( email_subject, email_content_text, email_content_html, creation_date ) VALUES ( '" . mysql_real_escape_string ( $_POST['email_subject'] ) . "', '" . mysql_real_escape_string ( $_POST['email_content_text'] ) . "', '" . mysql_real_escape_string ( $_POST['email_content_html'] ) . "', '" . date ( 'Y-m-d H:i:s' ) . "' )";
mysql_query ( $sql );

if ( strlen ( mysql_error() ) == 0 ) {
$listID = mysql_insert_id();

$sql = "SELECT id, email FROM email_marketing_contacts ORDER BY id ASC";
$rs = mysql_query ( $sql );
while ( $rw = mysql_fetch_assoc ( $rs ) ) {
$sql = "INSERT INTO email_marketing_emailstocrons ( listid, contactid, email ) VALUES ( '$listID', '" . $rw['id'] . "', '" . $rw['email'] . "' )";
mysql_query ( $sql );
$contatti_a_cron++;
}
}
}

if ( $contatti_a_cron > 0 ) echo '<p>Lista creata con successo! Aggiunti ' . $contatti_a_cron . ' contatti alla lista</p>';
?>

<form method="post">
Oggetto Email: <input type="text" name="email_subject" /><br />
Parte Testuale Email: <br />
<txtarea name="email_content_text" style="width: 1000px; height: 200px;"></txtarea><br />
Parte HTML Email: <br />
<txtarea name="email_content_html" style="width: 1000px; height: 200px;"></txtarea><br />
<input type="submit" value="Invia" />
</form>
```

**Codice 2: Invio delle Email Effettivo**

```
<?php
// CONNESSIONE AL DB - INSERIRE QUI

$sql = "SELECT * FROM email_marketing_lists WHERE active='1' LIMIT 1";
$rs = mysql_query ( $sql );
if ( $rs && mysql_num_rows ( $rs ) == 1 ) {
// esiste una lista attiva, vediamo che succede...
$rw = mysql_fetch_assoc ( $rs );

$listID = $rw['id'];
$subject = stripslashes ( $rw['email_subject'] );
$emailTextPart = wordwrap ( stripslashes ( $rw['email_content_text'] ), 50 );
$emailHtmlPart = wordwrap ( stripslashes ( $rw['email_content_html'] ), 50 );

$sql = "SELECT * FROM email_marketing_emailstocrons WHERE sent='0' AND listid='$listID' LIMIT 100";
$rs2 = mysql_query ( $sql );
if ( $rs2 && mysql_num_rows ( $rs2 ) >= 1 ) {
// invio effettivo delle email...

while ( $rw2 = mysql_fetch_assoc ( $rs2 ) ) {
// prima di tutto, rimpiazzo la variabile di UTENTE con una stringa calcolata adesso
$idUtente = base_convert( $rw2['contactid'] + 12445, 10, 36 );

// Invio effettivo della email con il metodo doppio
$random_hash = md5(microtime());
$header = "From: Quello che vuoi <quellochevuoi@ciaociao.it>\n";
$header .= "X-Mailer: PHP-simple-email-boundary\n";
$boundary = "==String_Boundary_x" . md5(time()). "x";
$header .= "MIME-Version: 1.0\n";
$header .= "Content-Type: multipart/alternative;\n";
$header .= " boundary=\"$boundary\";\n\n";

$messaggio = "Se visualizzi questo testo, manda una email ad quellochevuoi@ciaociao.it specificando che non e' stato possibile leggere questa email \n\n";
$messaggio .= "--$boundary\n";
$messaggio .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
$messaggio .= "Content-Transfer-Encoding: 7bit\n\n";
$messaggio .= str_replace ( '$$ID_UTENTE$$', $idUtente, $emailTextPart ) . "\n\n";
$messaggio .= "--$boundary\n";
$messaggio .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
$messaggio .= "Content-Transfer-Encoding: 7bit\n\n";
$messaggio .= str_replace ( '$$ID_UTENTE$$', $idUtente, $emailHtmlPart ) . "\n";

$status = mail( $rw2['email'], $subject, $messaggio, $header );

sleep ( 8 ); // mandiamone 1 ogni 8 secondi...

$sql = "UPDATE email_marketing_emailstocrons SET sent='1', sent_date='" . date ( 'Y-m-d H:i:s' ) . "', status='$status' WHERE id='" . $rw2['id'] . "'";
mysql_query ( $sql );
}
}
else {
// questa lista è stata completata! Quindi aggiorniamo la variabile "active" e settiamo la completion della lista ad adesso
$sql = "UPDATE email_marketing_lists SET active='0', completion_date='" . date ( 'Y-m-d H:i:s' ) . "' WHERE id='$listID'";
mysql_query ( $sql );
}
}
?>
```

**Codice 3: Pagina di Ponte da linkare nell'email, per fare in modo che l'utente faccia la sua scelta**

```
<html>
<head>
<title>pagina di ponte</title>
<style type="text/css">
* { font-family: "Lucida Sans","Lucida Sans Regular","Lucida Grande","Lucida Sans Unicode",Geneva,Verdana,sans-serif; margin: 0; outline: 0 none; padding: 0; }
body { background: none no-repeat scroll 0 0 #555555; font-size: 80%; }
div#wrapper { background: none no-repeat scroll 0 0 #FFFFFF; border-left: 1px solid #888888; border-right: 1px solid #888888; box-shadow: 0 0 15px 5px #FFFFEE; margin: 0 auto; padding: 0 15px; position: relative; width: 650px; }
div#header { height: 90px; position: relative; }
div#header div#logo { height: 90px; left: 0; position: absolute; top: 0; width: 500px; }
div#header div#logo a { background: url() no-repeat scroll 0 0 transparent; display: block; height: 90px; width: 315px; }
div#header div#logo h2 { color: #7CA431; font-size: 11px; left: 65px; padding: 1px 3px; position: absolute; top: 5px; }
div#header div#logo p { bottom: 0; color: transparent; font-size: 1px; height: 1px; left: -9000px; margin: 0; padding: 0; position: absolute; }
h1 strong, h1 strong, h3 strong { left: -9000px; position: absolute; text-indent: -9000px; top: 0; }
div#content { margin-top: 20px; }
h3 { margin: 5px 0; color: #007BB4; }
div#module { margin: 20px 0; border-top: 1px solid #888888; border-bottom: 1px solid #888888; background-color: #FFEEEE; padding: 30px; }

form { text-align: center; margin-top: 15px; }
form p { text-align: left; }
input.submit { border: 1px solid #007BB4; font-weight: bold; font-size: 16px; padding: 5px; background-color: #FFF; text-align: left; }
input.submit:hover { border: 1px solid #7CA431; background-color: #EEFFFF; }
</style>

<script type="text/javascript">
function checkCheckboxes () {

if ( ! document.getElementById ( 'infemails' ).checked && ! document.getElementById ( 'advemails' ).checked ) {
if ( ! document.getElementById ( 'infemails' ).checked ) {
var el = document.getElementById ( 'infemails' ).parentNode;
el.style.backgroundColor = '#FCAC98';
el.style.padding = '10px';
}
if ( ! document.getElementById ( 'advemails' ).checked ) {
var el = document.getElementById ( 'advemails' ).parentNode;
el.style.backgroundColor = '#FCAC98';
el.style.padding = '10px';
}
var go = confirm ( 'Per iscriverti alla newsletter, e\' necessario mettere la spunta sia su "email informative" sia su "email pubblicitarie".\nVuoi continuare lo stesso con questa scelta? Cosi\' facendo non sarai iscritto alla newsletter,\ne non potrai rimanere aggiornato sulle novita\'.' );

if ( go ) return true;
else return false;
}
else return true;
}
</script>
</head>
<body>
<div id="wrapper">
<div id="header">
<div id="logo">
logo & header
</div>
</div>
<?php
if ( isset ( $_POST['action'] ) && strlen ( $_POST['action'] ) > 0 ) {

// CONNESSIONE AL DB QUI

$id_utente = $_POST['id_utente'];

// gestione POST
switch ( $_POST['action'] ) {
case 'sub':
// sottoscrizione

$infemails = ( isset ( $_POST['infemails'] ) && $_POST['infemails'] == 1 ) ? 1 : 0;
$advemails = ( isset ( $_POST['advemails'] ) && $_POST['advemails'] == 1 ) ? 1 : 0;

$sql = "SELECT * FROM email_marketing_contacts WHERE id='$id_utente'";
$rs = mysql_query ( $sql );
if ( $rs && mysql_num_rows ( $rs ) == 1 ) {
$sql = "UPDATE email_marketing_contacts SET subscribed='1', unsubscribed='0', info_emails='$infemails', double_opt_in='$advemails' WHERE id='$id_utente'";
mysql_query ( $sql );
}
break;
case 'unsub':
// disiscrizione
$sql = "SELECT * FROM email_marketing_contacts WHERE id='$id_utente'";
$rs = mysql_query ( $sql );
if ( $rs && mysql_num_rows ( $rs ) == 1 ) {
$sql = "UPDATE email_marketing_contacts SET unsubscribed='1', subscribed='0', info_emails='0', double_opt_in='0' WHERE id='$id_utente'";
mysql_query ( $sql );
}
break;
default: break;
}
}
else if ( isset ( $_GET['u'] ) && strlen ( $_GET['u'] ) > 0 ) {
$idUtente = ( base_convert( $_GET['u'], 36, 10 ) - 12445 );
?>
<div id="content">
contenuto della email
</div>
<div id="module">
<h2>Modulo di iscrizione/disiscrizione alla Newsletter</h2>
<form method="post">
<input type="hidden" name="action" value="unsub" />
<input type="hidden" name="id_utente" value="<?php echo $idUtente; ?>" />
<input type="submit" class="submit" value="Disiscrivimi per sempre dalla lista" />
</form>
<h3 style="margin-top 15px; text-align: center;">... oppure ...</h3>
<form method="post" onsubmit="return checkCheckboxes();">
<p style="text-align: left; font-size: 14px; margin: 5px 0;">Mantienimi iscritto alle email informative: <input type="checkbox" name="infemails" id="infemails" value="1" /> <strong>*</strong></p>
<p style="text-align: left; font-size: 14px; margin: 5px 0;">Mantienimi iscritto alle email pubblicitarie: <input type="checkbox" name="advemails" id="advemails" value="1" /> <strong>*</strong></p>
<input type="hidden" name="id_utente" value="<?php echo $idUtente; ?>" />
<input type="hidden" name="action" value="sub" />
<input type="submit" class="submit" value="Rimani iscritto alla newsletter" />
<form>
<p> </p>
<p><strong>N.B.</strong></p>
<p>Per <strong>rimanere iscritti alla newsletter</strong>, è necessario rimanere iscritti <strong>sia alle email informative, sia alle email pubblicitarie.</strong></p>
</div>
<?php
}
else echo 'error';
?>
</div>
</body>
</html>
```

Capito tutto? In pratica, creiamo delle email con lo script 1. Le email saranno inviate in doppia modalità testuale+html, per rendere le email un pò più professionali. Questo significa **che dovrete creare un testo e un sorgente html per la vostra email**. Quindi, darete in pasto questi 2 sorgenti a questo script, che creerà un oggetto "email_marketing_lists" con oggetto, parte html e parte testo del vostro messaggio.

Una volta creata questa riga nel DB, non vi resterà che settare con un cronjob lo script di invio delle email ( il mio consiglio è di settare il cronjob per eseguire lo script ogni ora ).

Poi, tutto il resto lo farà la pagina di settaggio delle opzioni delle email degli utentu (script 3). Sarà vostro compito inserire, all'interno dell'email ( sia in formato testo che html ) un link alla pagina di modifica opzioni in questo formato:

**http://www.ilmiodominio.it/lamiacartella/unaltra/index.php?u=$$ID_UTENTE$$**

Lo script di invio delle email rimpiazzerà automaticamente questo placeholder con l'id effettivo del DB dei contatti di quella email. Il risultato? L'utente andrà a cliccare su un link che lo porterà ad una pagina che è già impostata sul suo id, quindi modificherà i dati suoi.

Avete visto quant'è semplice creare una lista di email double opt-in partendo da una lista che non è stata pensata per questo? **Qualsiasi email si può trasformare in un potenziale introito di denaro extra con le email pubblicitarie!**

Dall'articolo al lavoro vero

Se questo server lo devi tenere in piedi tu

Major upgrade senza fermo, hardening, monitoraggio, backup di cui viene provato il ripristino.

[Vedi come lavoro sui server](https://www.mauriziofonte.it/servizi/consulenza-it-devops.html) Ultima modifica: Lunedì 9 Mag 2011, alle 21:18 [« Articolo precedenteHow To Unblock Facebook, Youtube and Myspace - Zerofilters.info20 Dicembre 2010](https://www.mauriziofonte.it/blog/post/how_to_unblock_facebook_youtube_and_myspace_zerofilters.html)[Articolo successivo »Idraulico a Torino per installazione caldaie e prova fumi25 Giugno 2012](https://www.mauriziofonte.it/blog/post/idraulico-a-torino-per-installazione-caldaie-e-prova-fumi.html)

### Articoli correlati a Script PHP per la creazione di liste email double opt-in

- [Information gain e il March 2026 Core Update: scrivere contenuti che l'AI non comprime](https://www.mauriziofonte.it/blog/post/information-gain-march-2026-core-update-content-ai-generated.html)

  Il contenuto AI generated è una commodity che gli stessi LLM comprimono in una riga; l'information gain di prima mano no. Dopo il March 2026 · 24 Settembre 2026

  ![Information gain e il March 2026 Core Update: scrivere contenuti che l'AI non comprime](https://www.mauriziofonte.it/image/005370070-information-gain-march-2026-core-update-content-ai-generated.jpg)
- [Cloudflare blocca i crawler AI di default su tutti i piani, anche il tuo](https://www.mauriziofonte.it/blog/post/cloudflare-blocco-crawler-ai-default-free-tier-settembre-2026.html)

  Il 15 settembre 2026 Cloudflare ha cambiato i default dei suoi controlli sui crawler AI, e stavolta il cambio ha toccato anche i milioni di siti · 23 Settembre 2026

  ![Cloudflare blocca i crawler AI di default su tutti i piani, anche il tuo](https://www.mauriziofonte.it/image/005610070-cloudflare-blocco-crawler-ai-default-free-tier-settembre-2026.jpg)
- [Caching strategico con Redis in Laravel: il caso dei cataloghi e-commerce](https://www.mauriziofonte.it/blog/post/caching-strategico-redis-laravel-12-cataloghi-ecommerce.html)

  Un catalogo e commerce sotto carico vive o muore sul caching, ma cachare male serve dati sbagliati. Strategia con Redis in Laravel: cosa conviene · 3 Settembre 2026

  ![Caching strategico con Redis in Laravel: il caso dei cataloghi e-commerce](https://www.mauriziofonte.it/image/005220070-caching-strategico-redis-laravel-12-cataloghi-ecommerce.jpg)
- [Sincronizzare le identità Zitadel tra più ambienti senza trascinare il database](https://www.mauriziofonte.it/blog/post/zitadel-sincronizzazione-identita-cross-ambiente.html)

  Quando colleghi un'applicazione a un identity provider, ogni utente locale guadagna una colonna con l'identificativo esterno. Quella colonna · 12 Agosto 2026

  ![Sincronizzare le identità Zitadel tra più ambienti senza trascinare il database](https://www.mauriziofonte.it/image/005570070-zitadel-sincronizzazione-identita-cross-ambiente.jpg)
- [Cloudflare AI Crawl Control e Content Signals: governance del training crawler per il tuo blog aziendale](https://www.mauriziofonte.it/blog/post/cloudflare-ai-crawl-control-content-signals-bloccare-ai-training.html)

  Il crawl to referral ratio di Anthropic è 73.000:1, quello di OpenAI 1.700:1. Il deal storico 'contenuto in cambio di traffico' è rotto. Cloudflare · 22 Mag 2026

  ![Cloudflare AI Crawl Control e Content Signals: governance del training crawler per il tuo blog aziendale](https://www.mauriziofonte.it/image/004210070-cloudflare-ai-crawl-control-content-signals-bloccare-ai-training.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "Script PHP per la creazione di liste email double opt-in", mauriziofonte.it, 2011. https://www.mauriziofonte.it/blog/post/php-creazione-liste-email-double-optin.html

Pubblicato: 2011-05-09 · Aggiornato: 2011-05-09.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
