Talán sokaknak okozott már gondod a PHP kicsit fapados, viszont ennél fogva nagyon jól testre szabható mail() függvénye. Senki se szereti az ide vonatkozó RFC-ket túrni azért, hogy tudjon küldeni egy HTML levelet, vagy hogy egy képet tudjon csatolni a kiküldött levélhez.

A továbbiakban megnézzük, hogyan tudunk felépíteni egy HTML levelet, amihez egy képet csatoltunk hozzá. A dolog ott bonyolódik meg, hogy úgy szeretnénk azt a HTML levelet kiküldeni, hogy akinek az e-mail olvasója nem támogatja az ilyen leveleket az is el tudja majd olvasni. Azaz alternatívaként a levélben meg kell adnunk a sima szöveg változatot is.

A küldendő levél felépítése
A bal oldalamon látható, hogy hogyan fog felépülni az e-mail maga. A dolog lényege, hogy valami egyedi karaktersorozatot tartalmazó elválasztó egységekkel több részre bontjuk a levél tartalmát, és ezeknek a részeknek a típusát és azt, hogy az e-mail olvasó hogy kezelje őket, külön megadhatjuk. Tehát a levél kezdetben így fog kinézni:

--boundary_mixed
ide jön majd a levél szövege

--boundary_mixed
ide jön majd a kép

--boundary_mixed--

A "boundary_mixed" az egyedi azonosító, amivel daraboljuk a levelet. Új blokk kezdésénél két kötőjelet írunk az elválasztó elé, ha pedig le akarjuk zárni az utolsó blokkot, akkor az elválasztó elé és mögé is írunk két kötőjelet. A dolog ott bonyolódik csak meg egy picit, hogy a levél szövegét is több részre kell bontani majd, tehát egy lépéssel később a levél tartalma már így fog kinézni:

--boundary_mixed
Content-Type: multipart/alternative; boundary=boundary_alt

--boundary_alt
a levél sima szövege

--boundary_alt
a levél html szövege

--boundary_alt--

--boundary_mixed
ide jön majd a kép

--boundary_mixed--

Mint látszik, az első blokk elején megadtuk a blokk tartalmának a típusát (ezt majd a többi blokk kezdetnél is meg kell majd adnunk), amiben definiáltunk egy új elválasztó elemet. A multipart/alternative típus tulajdonsága, hogy a benne felsorolt blokkokból azt jeleníti meg, amelyiket a felhasználó e-mail olvasója támogat. Épp ezt akartuk elérni, hogy ha a kliens nem támogatja a HTML alapú leveleket, akkor a sima szöveget kapja meg. A levél tartalma így fog kinézni, miután mindenhol megadtuk a megfelelő fejléc elemeket:

--boundary_mixed
Content-Type: multipart/alternative; boundary=boundary_alt

--boundary_alt
Content-Type: text/plain; charset=iso-8859-2
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

a levél sima szövege

--boundary_alt
Content-Type: text/html; charset=iso-8859-2
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

a levél html szövege

--boundary_alt--

--boundary_mixed
Content-Type: image/gif; name=image.gif
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=image.gif

a kép base64-el elkódolva

--boundary_mixed--

A multipart résztől eltekintve a Content-Type fejléc teljesen hasonlóan viselkedik, mint a HTML-es fejlécek. A Content-Transfer-Encoding határozza meg, hogy milyen formátumban van az adott szöveg abban a blokkban. Kép esetén ez egy base64-es elkódolást jelent, szöveg esetén a quoted-printable értéket használjuk, aminek az esetén a blokk az ASCII karakterkészlet nyomtatható karaktereiből álló karakterláncot fog tartalmazni. A Content-Disposition azt adja meg, hogy a blokk a levél megjelenítésekor hogyan legyen kezelve (csatolt állományként (attachment), vagy jelenjen meg az e-mailben (inline)). A levél tartalma már megvan, most már csak a levél fejlécét kell megadnunk, ami annyiban módosul, hogy ott kell definiálnunk az első elválasztó elemünket (boundary_mixed) és meg kell adnunk a MIME verzióját:

From: a levél feladója
MIME-Version: 1.0
Content-type: multipart/mixed; boundary=boundary_mixed

Nincs más hátra, mint hogy ezt az egészet PHP-ben is megvalósítsuk, ami innentől már nem lesz egy bonyolult dolog:

$files   = array('image/gif' => 'image.gif');
$from    = 'a levél feladója';
$to      = 'a levél címzettje';
$subject = 'a levél témája';
$content = 'a levél tartalma, ami HTML-t is tartalmazhat';
 
$bd_mixed = md5(uniqid(rand(), true));
$bd_alt   = md5(uniqid(rand(), true));
 
$header =
'From: '.$from.'
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="'.$bd_mixed. '" ';
 
$text =
'--'.$bd_mixed. '
Content-Type: multipart/alternative; boundary="'.$bd_alt.'"
 
--'.$bd_alt.'
Content-Type: text/plain; charset=iso-8859-2
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
 
'.trim(strip_tags($content)).'
 
--'.$bd_alt.'
Content-Type: text/html; charset=iso-8859-2
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
 
'.$content.'
 
--'.$bd_alt.'--
 
';
 
foreach ($files as $mime => $name) {
	$text .=
'--'.$bd_mixed.'
Content-Type: '.$mime.'; name="'.$name.'"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="'.$name.'"
 
'.chunk_split(base64_encode(file_get_contents($name))).'
 
';
}
$text .= '--'.$bd_mixed.'--';
 
mail($to, $subject, $text, $header);

Ennyi lenne a kód, mint említettem, nem egy bonyolult dolog, a fentebb írt mail-darabolási ismeret birtokában. Talán csak a chunk_split függvény szorul némi magyarázatra: ha a szövegen kívül nem adunk meg neki más paramétert, akkor a 2045-ös RFC-nek megfelelő szemantika alapján 76 karakterenként tesz egy "\r\n"-t a szövegbe.

Erről ennyit, kellemes csatolt fájlokkal tűzdelt e-mail küldözgetést mindenkinek. :)

++++-

Hozzászólások Hozzászólások RSS

  1. Üdvözletem.

    Követtem az utasitásokat de nem jártam sikerrel.
    Megérkezik a levél de sajnos a levélben nem jelenik meg a kép csak a körvonala, és a csatolásban sem látható.

    Hírlevélhez szeretnék egy bannert küldeni, nem csatolni hanem csak megjeleniteni a képet.

    Tudnának segíteni?

  2. Ha a csatolt képet meg szeretnéd jeleníteni a HTML levélben, akkor szükség van még egy extra header-re, a Content-ID nevezetűre (a fenti kódban a foreach-en belül lévő header-ek közé kell tenni), ami valahogy így néz ki:

    Content-ID: <valami@valami>

    Aztán a levélben pedig ahova be akarod szúrni a képet:

    <img src="cid:valami@valami"/>

    Persze lehetőség van valamilyen tárhelyre feltöltenia képet és <img src="http://valami/valami.gif"/> kódot használni, csak a külső hivatkozásokat az e-mail kliensek nem mindig jelenítik meg.

  3. Köszönöm a leírást.

    Nekem a levél megérkezik de sajnos a csatolt állomány nem.

    Ha nem adunk meg a csatolt állománynak elérési utvonalat akkor hol kell lennie
    Köszönettel

    Zseni Ferenc

    Zseni FerencJanuary 26, 2007
  4. Minden elérési út nélkül a php fájllal egy könyvtárban.

  5. Üdvözöllek!
    Had kezdjem hízelgéssel, igazán kíváló összeszedett a fenti anyag.
    Tudtam is csatolt file-okat küldeni, és már nagyon elégedett kezdtem lenni, amikor is szerettem volna a html oldalban a linkelt képet megjeleníteni. Nem sikerült.
    Kérdésem a kódban a / tévedés vagy szükséges.

    Továbbá ha a
    a csatolt file neve image.gif, és
    Content-Transfer-Encoding: base64
    sor után beteszem, hogy mondjuk:
    Content-ID: -et
    és a html-be pedig a
    -t
    akkor miért nem jelenik meg a kép.

    Szóval már majdnem mindent értek, csak azt nem, hogy a html.ben levő kép nevének mivel kell megegyeznie, a csatolt file nevével, vagy a Cintent-ID-ben levővel, vagy ...

    Valamint: a valami@valami példából az (is) kiolvasható hogy abban a @ karakternek szerepelniekell, vagy csak én bonyolítom?

    És végül: az
    sem működik, pedig a file ott van.

    (Microsoft outlook-ot használok, és kapok olyan leveleket, amelyek html-ek és meg is jelennek a képek)

    Várom szíves segítségeteket.
    Tisztelettel: Nagy Miklós

    namikiOctober 15, 2007
  6. A fenti hozzászólásomból eltüntek elküldés után a kódok. Hogy tudok úgy írni, hogy azt lásd amit írok?
    Vagy ha kitennél néhány sort ami egy adott levélhez csatol egy képet, és azt automatikusan meg is jeleníti + a fentiismertetőddel már boldogulnék.
    Előre is köszönöm.

    namikiOctober 15, 2007
  7. A kód végi foreach-be kell (például) a Content-Disposition: sor alá valami olyasmi sor, hogy

    Content-ID: <'.$name.'@valami>

    A fenti példa esetében ugye a $name az image.gif, tehát a HTML-be ezt kell írni, hogy megjelenjen a kép:

    <img src="cid:image.gif@valami"/>

    A @ utáni rész elméletileg a küldő domainje (Mozilla Thunderbird azt írja oda, és az RFC 21111 példáiból is ez jön le: http://www.faqs.org/rfcs/rfc2111.html), tehát ha a feladó valaki@tesztemailcim.hu akkor tesztemailcim.hu.

  8. Ha a megjelenítendő kódokban < és > helyett &lt; és &gt; -t írsz, akkor megjelennek rendesen. Különben a WordPress valószínűleg nem engedélyezett HTML kódnak nézi, és megeszi.

  9. Aki szépen akarja megoldani a feladatot: PHPMailer.

    bhMarch 2, 2010

Szólj hozzá!

regisztráció, bejelentkezés

Az oldalon nem jelenik meg.

Ezeket a tageket használhatod: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>