back to top

Inviare email con allegati usando PHP

Purtroppo PHP non offre un metodo intuitivo ed immediato per l’invio di email con allegati: per questo motivo spesso si fa ricorso a delle apposite classi (come PHPMailer) per gestire con maggior semplicità questa esigenza. L’utilizzo di classi esterne, seppur comodo, non è tuttavia indispensabile. Con un poco di pazienza, infatti, possiamo scrivere noi stessi il codice PHP per l’invio di email con allegati (cd: attachments) utilizzando la classica funzione mail() integrata nativamente nel linguaggio.

L’allegato, infatti, altro non è che una sorta di "inclusione" di un file all’interno di una mail. Per fare ciò si ricorre al formato MIME multi-part che consente, appunto, di creare una mail suddivisa in diverse parti. La nostra mail, quindi, avrà una semplice parte testuale (il messaggio vero e proprio) ed una parte più complessa contenente l’allegato.

In questo articolo vedremo come creare una sorta di formmail attraverso il quale gli utenti del nostro sito potranno inviarci file in allegato tramite un semplice modulo di upload.

Per raggiungere il nostro scopo realizzeremo due file distinti: un semplice file .html contenente il form ed un file .php che svolgerà tutto il lavoro di elaborazione. Precisamente, il nostro script PHP (che chiameremo formmail.php) dovrà occuparsi dei seguenti compiti:

  1. Recupero delle informazioni inserite nel form
  2. Recupero e verifica del file allegato
  3. Creazione del messaggio MIME multi-part
  4. Spedizione della email

Ma per prima cosa vediamo il file .html contenente il form:

<form action="formmail.php" method="POST" enctype="multipart/form-data">
<table border="0">
<tr>
  <td>Tua Mail:</td>
  <td><input type="text" name="mittente" value="" /></td>
</tr>
<tr>
  <td>Oggetto:</td>
  <td><input type="text" name="oggetto" value="" /></td>
</tr>
<tr>
  <td>Messaggio:</td>
  <td><textarea cols="20" rows="4" name="messaggio"></textarea></td>
</tr>
<tr>
  <td>Allega file:</td>
  <td><input type="file" name="allegato" /></td>
</tr>
<tr>
  <td colspan="2"><input type="submit" value="Invia" /></td>
</tr>
</table>
</form>

Non credo sia il caso di soffermarsi sul codice visto sopra in quanto si tratta di una semplice tabella HTML contenente un semplice form. L’unica cosa degna di nota è l’aggiunta di:

enctype="multipart/form-data"

al tag FORM. Questo accorgimento è necessario per la corretta gestione, tramite protocollo HTTP, dell’invio di file mediante il modulo.

Vediamo ora il codice PHP vero e proprio. Data la complessità di alcuni passaggi ho ritenuto opportuno aggiungere ampi commenti che, una volta compresi, potrete agevolmente eliminare dal vostro script:

<?php
// Recupero il valore dei campi del form
$destinatario = 'info@mail-del-sito.com';
$mittente = $_POST['mittente'];
$oggetto = $_POST['oggetto'];
$messaggio = $_POST['messaggio'];

// Valorizzo le variabili relative all'allegato
$allegato = $_FILES['allegato']['tmp_name'];
$allegato_type = $_FILES['allegato']['type'];
$allegato_name = $_FILES['allegato']['name'];

// Creo altre due variabili ad uno interno
$headers = "From: " . $mittente;
$msg = "";

// Verifico se il file è stato caricato correttamente via HTTP
// In caso affermativo proseguo nel lavoro...
if (is_uploaded_file($allegato))
{
  // Apro e leggo il file allegato
  $file = fopen($allegato,'rb');
  $data = fread($file, filesize($allegato));
  fclose($file);

  // Adatto il file al formato MIME base64 usando base64_encode
  $data = chunk_split(base64_encode($data));

  // Genero il "separatore"
  // Serve per dividere, appunto, le varie parti del messaggio.
  // Nel nostro caso separerà la parte testuale dall'allegato
  $semi_rand = md5(time());
  $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
  
  // Aggiungo le intestazioni necessarie per l'allegato
  $headers .= "\nMIME-Version: 1.0\n";
  $headers .= "Content-Type: multipart/mixed;\n";
  $headers .= " boundary=\"{$mime_boundary}\"";

  // Definisco il tipo di messaggio (MIME/multi-part)
  $msg .= "This is a multi-part message in MIME format.\n\n";

  // Metto il separatore
  $msg .= "--{$mime_boundary}\n";

  // Questa è la parte "testuale" del messaggio
  $msg .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
  $msg .= "Content-Transfer-Encoding: 7bit\n\n";
  $msg .= $messaggio . "\n\n";

  // Metto il separatore
  $msg .= "--{$mime_boundary}\n";

  // Aggiungo l'allegato al messaggio
  $msg .= "Content-Disposition: attachment; filename=\"{$allegato_name}\"\n";
  $msg .= "Content-Transfer-Encoding: base64\n\n";
  $msg .= $data . "\n\n";

  // chiudo con il separatore
  $msg .= "--{$mime_boundary}--\n";
}
// se non è stato caricato alcun file
// preparo un semplice messaggio testuale
else
{
  $msg = $messaggio;
}

// Invio la mail
if (mail($destinatario, $oggetto, $msg, $headers))
{
  echo "<p>Mail inviata con successo!</p>";
}else{
  echo "<p>Errore!</p>";
}
?>

Da segnalare, nella gestione dell’allegato, l’utilizzo dell’encoding base 64. E’ stato, pertanto, necessario compiere alcune operazioni sul file: lo abbiamo aperto (abbiamo usato fopen con "rb" – read binary), ne abbiamo estratto il contenuto (usando fread) e lo abbiamo passato alla funzione base64_encode (abbiamo usato chunk_split per suddividere la stringa restituita da base64_encode in segmenti più ridotti).

Concludo ricordando che il codice qui proposto ha puramente finalità didattica: prima di essere messo in produzione, infatti, dovrebbe essere arricchito di una serie di controlli circa la corretta compilazione dei campi del form oltre che sul tipo di file che l’utente sta cercando di inviarci.

Altri contenuti interessanti

Pubblicità
Massimiliano Bossi
Massimiliano Bossi
Stregato dalla rete sin dai tempi delle BBS e dei modem a 2.400 baud, ho avuto la fortuna di poter trasformare la mia passione in un lavoro (nonostante una Laurea in Giurisprudenza). Adoro scrivere codice e mi occupo quotidianamente di comunicazione, design e nuovi media digitali. Orgogliosamente "nerd" sono il fondatore di MRW.it (per il quale ho scritto centinaia di articoli) e di una nota Web-Agency (dove seguo in prima persona progetti digitali per numerosi clienti sia in Italia che all'estero).

Leggi anche...

Cannot modify header information – headers already sent: come risolvere l’errore PHP

L'errore di PHP cannot modify header information - headers...

Ricavare l’estensione di un file con PHP

Quando si lavora con i file in un'applicazione web,...

GD Library: creazione, manipolazione e ridimensionamento immagini con PHP

Le librerie GD (o GD Library), sono componenti fondamentali...

PHP: impostare il fuso orario italiano

Le tue pagine PHP non mostrano l’orario corretto? Probabilmente...

5 script PHP per gestire BBCode

A volte può aversi l'esigenza di dover offrire agli...
Pubblicità