Skicka och formattera email i PHP?

Av Joakim 'Taurus' Andersson

Denna lilla guide visar hur man skickar och formatterar email på ett riktigt sätt i PHP.

Konfiguration


Till att börja med måste din php.ini vara rätt konfigurerad. Har du din sida på ett webbhotel är det inte mycket att göra annat än att skälla på webbhotelet om det inte fungerar. Nja, det är inte riktigt sant för det finns några andra möjligheter. Inställningarna som är relevanta för Windows går att ändra med ini_set() eller i en .htaccess-fil. Det går också att skicka email direkt mot en smtp-server vilket vi tittar på lite längre ner i guiden.

Kör du en egen webbserver på Windows så kan du använda dig av din internetleverantörs smtp-server. Så länge det inte handlar om enorma mängder mail så ska det inte vara några problem. Smtp-servern bryr sig egentligen inte om mailet kommer från din mailklient eller från ett PHP-skript. Att sätta upp en egen smtp-server bör undvikas om man inte är medveten om säkerhetsluckorna och hur man förhindrar dom. Det var på grund av felkonfigurerade smtp-servrar hos sina kunder som Telia och ComHem? valde att spärra port 25 inåt.
SMTP = smtp.din-isp.nu
sendmail_from = din_mail@din-isp.nu

I *NIX ska inte ovanstående direktiv användas utan man ska istället ange sökvägen till sendmail.
sendmail_path = /usr/bin/sendmail
Här kan man även ange växlar till sendmail om det skulle behövas.

Kom ihåg att starta om webbservern för att ändringarna ska slå igenom!

Att skicka mail


Detta exempel är ganska självförklarande. Det skickar ett mail med rubriken Min Rubrik till taurus@min-isp.net och innehållet hamnar på 3 separata rader.
<?php
   $to = "taurus@min-isp.nu";
   $subject = "Min rubrik";
   $body = "Rad 1\r\nRad 2\r\nRad 3";

   mail($to , $subject, $body);
?>
Då var allting klart då! Eller var det verkligen det?
Nej inte riktigt. Även om ovanstående exempel fungerar (om man anger en giltig email-adress) så finns det några problem.

1. Vem är mailet skickat från?
I *NIX skickas mailet från användaren som webbservern körs med. I Windows är det inställningen sendmail_from som används. Kommer du ihåg att du kan påverka den inställningen med ini_set()? Det är ett sätt att lösa det på. Ett annat sätt som fungerar i både *NIX och Windows är att sätta ett värde på From i mailhuvudet. Det görs i variabeln $headers i exemplet nedan.
<?php
   $to = "taurus@min-isp.nu";
   $subject = "Min rubrik";
   $body = "Rad 1\r\nRad 2\r\nRad 3";
   $headers = "From: jocke@min-isp.nu";

   mail($to , $subject, $body, $headers);
?>

2. Man vill skicka till flera mottagare.
Tänk på att PHP inte är lämpat att skicka ut mail till större antal mottagare. Det finns andra programvaror som hanterar detta mycket bättre.
Rör det sig om ett mindre antal mottagare går det att lösa på några olika sätt.
Alternativ 1. Lägg in flera mottagare i $to:
   $to = "taurus@min-isp.nu, nisse@annan-isp.nu";
Nackdelen med detta är att alla mottagare syns i mailet vilket kanske inte är önskvärt i alla lägen.

Alternativ 2. Lägg till Cc eller Bcc i mailhuvudet.
   $headers = "From: jocke@min-isp.nu\r\n";
   $headers .= "Bcc: nisse@annan-isp.nu";
Bcc står för Blind Carbon Copy vilket betyder ungefär 'osynlig kopia'. Mottagare som står i Bcc kommer inte att synas i mailet hos någon.

Alternativ 3. Loopa igenom alla mottagare.
<?php
   $array_to = array("taurus@min-isp.nu", "nisse@annan-isp.nu", "berra@annan-isp.nu");
   $subject = "Min rubrik";
   $body = "Rad 1\r\nRad 2\r\nRad 3";
   $headers = "From: jocke@min-isp.nu";

   foreach($array_to as $to) {
      mail($to , $subject, $body, $headers);
   }
?>

3. Vad händer med åäö i mailet?
Det är här dom flesta gör fel. Att bara skicka iväg ett mail fullt med åäö och andra 8-bitarstecken kommer att generera ett mail som inte följer de RFC:er som beskriver hur mail ska se ut. Det är också detta som är orsaken till att den här guiden blev till! Felaktiga mail kan orsaka en del underliga fel. En del mailservrar genererar ett felmeddelande, åäö kan visas felaktigt och så vidare. Vissa mailservrar kan dessutom vara konfigurerade att inte släppa igenom 'trasiga' mail!

Hur ska man då göra?
Häng med i nästa del där vi även går igenom hur man skickar html-mail och bifogar filer.

Formattering av mail


Lösningen för att skicka mail i olika format och med bifogade filer heter MIME vilket står för Multipurpose Internet Mail Extension. Att formattera ett mail och bifoga filer är inte det enklaste. Det är ganska mycket man måste tänka på för att det ska bli rätt. Som tur är finns det ett färdiga klasser för det här redan så varför uppfinna hjulet igen?

Vi kommer att använda oss av klasserna Mail och Mail_mime från Pear för detta. Normalt har du redan Pear installerat och man behöver bara se till att include_path även pekar på katalogen med Pear. Var den finns varierar beroende på operativsystem och din installation.

<?php
   include("Mail.php");
   include("Mail/mime.php");

   $text = "Textversion av mailet. Med åäö...";
   $crlf = "\r\n";
   $hdrs = array(
         "From"    => "jocke@min-isp.nu",
         "Subject" => "Testmail med åäö i rubriken"
      );
   $params = array(
         "text_encoding" => "quoted-printable"
      );

   $mime = new Mail_mime($crlf);
   $mime->setTXTBody($text);
   $body = $mime->get($params);
   $hdrs = $mime->headers($hdrs);

   $mail =& Mail::factory("mail");
   $mail->send("taurus@min-isp.nu", $hdrs, $body);
?>
Först inkluderas Mail.php och Mail/mime.php från Pear.
Andra delen sätter några variabler.
  • $text innehåller texten som ska vara i mailet.
  • $crlf ska normalt vara "\r\n" men kan i vissa fall behöva ändras till "\n"
  • $hdrs är en array som innehåller de delar av mailhuvudet som inte Mail_mime genererar. Där kan man lägga till sina CC och Bcc om man vill det.
  • $params är en array som innehåller inställningar för Mail_mime. Det enda vi ställer in just nu är att text ska kodas med metoden 'quoted-printable'. Standard för Mail_mime är 7bit-kodning för 'text/plain' och det vill vi inte ha eftersom vi har åäö i mailet.
I tredje delen av skriptet så skapas en instans av klassen Mail_mime. Texten, inställningarna och våra extra mailhuvuden skickas in och ut får vi $body och $hdrs som nu är kodade på rätt sätt.
I sista delen skapas en instans av Mail och mailet skickas iväg.

Som du ser i exemplet ovan så använder vi oss inte av PHPs inbyggda funktion mail() längre utan nu skickas mailet med Pear-klassen Mail istället. Med några små ändringar skulle det gå att skicka mailet med mail(), men den här klassen har några små extra finesser som vi ska titta på lite längre ner.

Nästa exempel visar hur man skickar html-mail.
<?php
   include("Mail.php");
   include("Mail/mime.php");

   $text = "Textversion av mailet. Med åäö...";
   $html = "<html><body>HTML-version av mailet. Med åäö...</body></html>"; // Ny rad
   $crlf = "\r\n";
   $hdrs = array(
         "From"    => "jocke@min-isp.nu",
         "Subject" => "Testmail med åäö i rubriken"
      );
   $params = array(
         "text_encoding" => "quoted-printable"
      );

   $mime = new Mail_mime($crlf);
   $mime->setTXTBody($text);
   $mime->setHTMLBody($html); // Ny rad
   $body = $mime->get($params);
   $hdrs = $mime->headers($hdrs);

   $mail =& Mail::factory("mail");
   $mail->send("taurus@min-isp.nu", $hdrs, $body);
?>
Endast två nya rader, här markerade med '// Ny rad', behövs för att det ska fungera. Nu innehåller mailet två olika delar. Den ena är i 'text/plain' och den andra i 'text/html'. Det är fullt möjligt att skicka ett mail enbart i html, men så länge man inte vet vad mottagaren föredrar så ska man skicka antingen enbart text eller både text och html.

Hur gör man om man vill ha med bilder i sitt html-mail?
Ett sätt är att länka till en bild på en webbserver någonstans.
   $html = "<html><body>HTML-version av mailet. Med åäö...<br><img src=\"http://www.min-server.nu/image.jpg\"></body></html>";
Detta fungerar, men bilden kommer att laddas ner varje gång mailet ska visas.
Det andra sättet är att bara ange filnamnet på bilden och sedan inkludera bilden i mailet. Med Mail_mime är detta ganska enkelt.
<?php
   include("Mail.php");
   include("Mail/mime.php");

   $text = "Textversion av mailet. Med åäö...";
   $html = "<html><body>HTML-version av mailet. Med åäö...<br><img src=\"image.jpg\"></body></html>"; // Andrad rad
   $image = "/path/to/image.jpg"; // Ny rad
   $image_type = "image/jpeg"; // Ny rad
   $crlf = "\r\n";
   $hdrs = array(
         "From"    => "jocke@min-isp.nu",
         "Subject" => "Testmail med åäö i rubriken"
      );
   $params = array(
         "text_encoding" => "quoted-printable"
      );

   $mime = new Mail_mime($crlf);
   $mime->setTXTBody($text);
   $mime->setHTMLBody($html);
   $mime->addHTMLImage($image, $image_type); // Ny rad
   $body = $mime->get($params);
   $hdrs = $mime->headers($hdrs);

   $mail =& Mail::factory("mail");
   $mail->send("taurus@min-isp.nu", $hdrs, $body);
?>
Här har vi ändrat html-koden som ska skickas och lagt till några nya rader.
$image innehåller sökvägen till bilden som ska bifogas och $image_type innehåller mime-typen för bilden.
Raden $mime->addHTMLImage($image, $image_type); kodar och lägger till bilden i mailet. Detta måste göras för varje bild som ska bifogas i mailet.

Mail_mime kan även användas för att bifoga andra filer i mailen.
<?php
   include("Mail.php");
   include("Mail/mime.php");

   $text = "Textversion av mailet. Med åäö...";
   $file = "/sökväg/till/din/fil.txt"; // Ny rad
   $crlf = "\r\n";
   $hdrs = array(
         "From"    => "jocke@min-isp.nu",
         "Subject" => "Testmail med åäö i rubriken"
      );
   $params = array(
         "text_encoding" => "quoted-printable"
      );

   $mime = new Mail_mime($crlf);
   $mime->setTXTBody($text);
   $mime->addAttachment($file); // Ny rad
   $body = $mime->get($params);
   $hdrs = $mime->headers($hdrs);

   $mail =& Mail::factory("mail");
   $mail->send("taurus@min-isp.nu", $hdrs, $body);
?>
$file är ingen överaskning. Den innehåller sökvägen till filen som ska bifogas.
Raden $mime->addAttachment($file); bifogar filen. Här kan man även ange MIME-typ för filen men som standard är den 'application/octet-stream' och det passar bra här.

Skicka mail utan att använda mail()


Även om det inte har sett så ut så har vi faktiskt använt oss av funktionen mail() för att skicka våra email i de senaste skripten för det är nämligen så klassen Mail skickar mailen. Hur gör man då för att skicka mailet direkt till en smtp-server?
Det kan inte bli mycket enklare. Klassen Mail hanterar nämligen det också!

Sätt några parametrar och ändra metoden som Mail ska använda så ska det fungera.
   $mail_params = array(
         "host"      => "din.smtp-server.nu",
         "port"      => 25
      );
   $mail =& Mail::factory("smtp", $mail_params);
   $mail->send("taurus@min-isp.nu", $hdrs, $body);
Om smtp-servern kräver inloggning för att få skicka mail så ändrar man $mail_params till
   $mail_params = array(
         "host"      => "din.smtp-server.nu",
         "port"      => 25,
         "auth"      => true,
         "username"  => "login",
         "password"  => "password"
      );

Referenser


http://www.php.net/manual/en/ref.mail.php
http://pear.php.net/manual/en/package.mail.php
http://pear.php.net/manual/en/package.mail.mail-mime.php

Kommentarer

Ändra helst inte i dokumentet utan lägg dina kommentarer och förslag på ändringar här:
Wiki-navigering
Wiki Index
Wiki Artiklar
Wiki Skolan
Wiki Guider
Wiki FAQ
Webbhotell
Domänregistrering
Wiki-sökning
Sök:
Dokumentalternativ
Redigera dokumentet
Visa dokumenthistorien
Senaste wiki-ändringar
Visa ändringarna
Inställningar
Wiki inställningar
Bra att veta
Vad är en Wiki?
Våra förhållningsregler
Trivselregler
Att använda Wikin
Kontakta oss på adressen: info@phpportalen.net
Webbplatsen bygger i grunden på phpBB 2.0.4 © 2001, 2002 phpBB Group

Modifieringar har senare gjorts i systemet av PHPportalen
Sid och logotypdesign skapad av Daren Jularic