Ukázky · 2026

Truhlárna Smrk

Ukázka opravy kontaktního formuláře v PHP. Správné hlavičky e-mailu, nastavení SPF, DKIM a DMARC a ochrana proti zneužití.

TRUHLÁRNA SMRK

Shrnutí pro zájemce o web

Truhlárna Smrk má na webu kontaktní formulář. Návštěvník ho odešle, uvidí poděkování, a přesto část zpráv majiteli nikdy nedorazí. Poptávky tiše mizí a nikdo o tom neví. Na takové závadě je nejhorší právě to, že web vypadá, jako by fungoval.

Příčina byla ve způsobu, jakým formulář e-mail odesílal. Oprava spočívala v tom, že se formulář přestal vydávat za návštěvníka a doména dostala správné ověřovací záznamy. Zpráva teď dorazí do schránky a odpovědět zákazníkovi stačí jedním kliknutím.

Příčina

Formulář vkládal do hlavičky From adresu návštěvníka, například jan@gmail.com, ale zprávu fyzicky odesílal server hostingu. Přijímající server tak vidí zprávu, která tvrdí, že přichází z Gmailu, a odesílá ji cizí server bez oprávnění. Kontrola SPF, DKIM a DMARC selže a zpráva skončí ve spamu, nebo je rovnou odmítnuta.

Druhý problém byl v tom, že funkce mail() vrací true, jakmile zprávu převezme odesílací server. Neříká nic o tom, zda dorazila. Formulář proto hlásil úspěch i při nedoručení.

Oprava

  • Odesílatel: From je pevná adresa na vlastní doméně, adresa návštěvníka jde do Reply-To.
  • Obálka zprávy: pátý parametr mail() (-f) nastaví stejnou adresu i jako envelope sender, který kontroluje SPF.
  • SPF: TXT záznam domény povolí servery hostingu. Doména smí mít jen jeden SPF záznam, jinak se kontrola nevyhodnotí.
  • DKIM: podpis zapnutý u hostingu a veřejný klíč v DNS pod příslušným selektorem.
  • DMARC: záznam _dmarc začíná na p=none s adresou pro reporty. Po několika týdnech sledování se zpřísní na quarantine.
  • Zabezpečení: zalomení řádků se z jména odstraní (ochrana proti vkládání hlaviček), e-mail se ověří přes FILTER_VALIDATE_EMAIL, skryté pole zachytává roboty a předmět s diakritikou se kóduje podle RFC 2047.
$name = trim(str_replace(["\r", "\n"], ' ', $_POST['name'] ?? ''));
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);

if ($email === false || $name === '') {
    http_response_code(422);
    exit;
}

$subject = '=?UTF-8?B?' . base64_encode('Poptávka z webu') . '?=';

$headers = [
    'From' => 'Formulář <formular@priklad.cz>',
    'Reply-To' => $email,
    'Content-Type' => 'text/plain; charset=UTF-8',
];

$sent = mail($to, $subject, $message, $headers, '-fformular@priklad.cz');

Pole hlaviček v mail() vyžaduje PHP 7.2 a novější.

Jak jsem ověřil, že to funguje

Zkušební zprávu jsem poslal na Gmail a v zobrazení původní zprávy zkontroloval, že SPF, DKIM i DMARC mají výsledek PASS. Totéž jsem zkusil na adresu u Seznamu. Když mail() selže, formulář nově zobrazí chybu s telefonním číslem. Každá odeslaná zpráva se navíc zapisuje do souboru mimo veřejný adresář s omezenou dobou uchování, takže poptávka nezmizí ani při výpadku e-mailu.

Proč je to v portfoliu

Jde o modelový případ, ale závada je jedna z nejčastějších, se kterými se u cizích webů setkávám. Ukazuje můj postup při opravách: nejdřív najít skutečnou příčinu, ne jen přidat další odesílací službu, a nakonec ověřit výsledek na reálných schránkách.

Přijímám nové projekty

Web nefunguje? Nečekejte, až to poznají zákazníci.

Napište, co nefunguje a komu to komplikuje práci. Ozvu se vám s návrhem postupu a cenou.