Skip to content
Kundecaser

Kontaktskjemaet meldte suksess, e-postene kom aldri fram

10. august 2026 · Nordic Digi Solutions · 6 min lesetid

En kunde tok kontakt en fredag morgen med et akutt problem: kontaktskjemaet på nettstedet hadde sluttet å sende e-post. Nye henvendelser dukket fortsatt opp i databasen, så selve skjemaet virket åpenbart, men ingenting nådde fram til noen innboks. De hadde testet selv og fikk ingenting. For en virksomhet som får nesten alle henvendelser gjennom det ene skjemaet, var dette tapt omsetning, ikke en feilrapport. Vi hadde diagnostisert, bygget om og verifisert det før lunsj.

Kort om oppdraget

  • Plattform: Egenutviklet PHP-applikasjon på delt webhotell
  • E-post: Google Workspace, altså nettsted og postkasser hos hver sin leverandør
  • Symptom: Skjemaet lagret hver henvendelse, men ingen e-postvarsler kom fram
  • Tidsbruk: Meldt før klokken 9, løst og verifisert 11:30 samme formiddag

Utfordringen

Nettstedet var en PHP-applikasjon som hadde levd lenge, på et vanlig delt webhotell, med tre separate skjemaer som alle matet én felles behandler. Behandleren gjorde to ting ved innsending: skrev henvendelsen til en MySQL-database, og sendte et varsel på e-post til teamet.

Databasedelen fungerte perfekt. Hver eneste henvendelse lå der. E-postdelen produserte ingenting, uten en eneste feilmelding noe sted som kunne forklare det.

Verre: systemet meldte aktivt at alt gikk bra. Applikasjonen lagret en leveringsstatus på hver henvendelse, og hver eneste rad sa at e-posten var sendt.

Undersøkelsen

Hva sendeloggen faktisk viste

Vi begynte i sendeloggen, og den snudde problemstillingen med én gang. Over rundt 1 800 innsendinger flere måneder tilbake hadde PHP-funksjonen mail() returnert true hver eneste gang. Ikke én registrert feil, heller ikke på kundens egen test.

Det var nøkkelen. mail() rapporterer ikke levering. Den rapporterer bare at den lokale e-postserveren tok imot meldingen for videre behandling. Den returnerer true og går videre, uansett hva som skjer etterpå.

Feilen lå altså ikke i applikasjonen. Den satt et sted mellom webserveren og innboksen, og koden hadde ingen innsyn i det gapet.

Kartlegging av e-postveien

Kartleggingen forklarte hvorfor. Nettstedet kjørte på webhotell, mens virksomhetens postkasser lå i Google Workspace. Hvert varsel ble derfor sendt som bedriftens eget domene, til bedriftens eget domene, fra en maskin som ikke var Google. Vi fant også at avsenderautentiseringen på domenet var slapp og ufullstendig. SPF, DKIM og DMARC ga Google ingen sterke grunner til å stole på meldingene.

Det er en skjør ordning selv på en god dag. Om meldingen ble forkastet før den forlot webhotellet, eller filtrert ved ankomst, ble utfallet for kunden det samme: stillhet.

Oppsettet er svært vanlig i Norge. Nettstedet ligger hos et norsk webhotell, e-posten ligger i Google Workspace eller Microsoft 365, og de to ble satt opp av ulike personer på ulike tidspunkt. Strekningen mellom dem er det ingen som eier.

Derfor oppdaget ingen det tidligere

Leveringsstatusfeltet i databasen lagret returverdien fra mail(), altså nøyaktig den verdien som alltid var true. Overvåkingen rapporterte trofast helsetilstanden til feil ting.

Løsningen

Vi sluttet å lete etter hvilken komponent nedstrøms som spiste e-posten, og fjernet avhengigheten i stedet. Hvis meldingen aldri må krysse fra webhotellet og inn til Google, kan ingen av de to mulige årsakene inntreffe.

Vi bygget om utsendingen til autentisert SMTP rett mot Google Workspace, med PHPMailer-biblioteket som allerede lå i prosjektet. Meldingene har nå sitt utspring inne i kundens eget e-postmiljø og leveres internt.

Tre ting var viktige i måten vi rullet det ut på:

  • En trygg utrulling. Den nye veien faller automatisk tilbake til den gamle metoden hvis legitimasjonen mangler, slik at skjemaet i drift ikke kunne knekke midt i utrullingen.
  • Ærlig rapportering. Feil returnerer nå den faktiske SMTP-feilen, som skrives både til loggen og til raden for henvendelsen. Leveringsstatusfeltet betyr endelig noe.
  • En feil nummer to fjernet. Mens vi leste behandleren fant vi en utsending som lå utenfor betingelsen sin. Den fyrte av på hver eneste innsending, med feilformede headere, og sendte interne data om henvendelsen til den besøkendes egen adresse. Den hadde kjørt ubemerket på hver eneste henvendelse.

Resultatet

Den første innsendingen etter utrulling bekreftet fiksen på to måter. Loggen viste en ren sending uten markør for reservemetoden, altså at den autentiserte veien var brukt. Og tidsstemplene viste to sekunder mellom sammensetting og sending, som er tur-retur i en ekte SMTP-samtale. Det gamle mail()-kallet returnerte umiddelbart, og det er nøyaktig grunnen til at det aldri kunne fortelle noen noe nyttig.

  • ✅ Meldt før klokken 9, løst og verifisert 11:30 samme formiddag
  • ✅ Kunden bekreftet mottak minutter etter utrulling
  • ✅ Utsending går nå på autentisert SMTP inne i kundens eget e-postmiljø
  • ✅ Feil rapporterer den reelle SMTP-feilen i stedet for et meningsløst suksessflagg
  • ✅ En separat feil som sendte interne henvendelsesdata til besøkende ble funnet og fjernet
  • ✅ Alle henvendelser som kom inn mens feilen pågikk ble hentet ut av databasen

Ingenting gikk tapt. Henvendelsene nådde bare aldri fram til noen. Vi leverte etterslepet for oppfølging, med én advarsel: den historiske leveringsstatuskolonnen kunne ikke stoles på, fordi den hadde registrert suksess for meldinger som aldri kom fram.

Lærdommen

Sendt er ikke det samme som levert. PHP-funksjonen mail() bekrefter overlevering, ikke mottak. Et system som behandler returverdien som bevis på levering, overvåker ingenting.

Delt hosting er der e-post knekker stille. Når nettstedet og postkassene ligger hos hver sin leverandør, er det skjørt å sende som ditt eget domene fra webserveren. Autentiser mot leverandøren som faktisk holder postkassene.

Registrer utfall, ikke returverdier. Et statusfelt som bare kan si suksess er verre enn ikke noe statusfelt i det hele tatt, fordi det produserer falsk trygghet.

Feiltypen du skal frykte er den stille. Denne stansen ble ikke fanget av logger, varsler eller dashbord. Den ble fanget av at en kunde la merke til noe. Det er argumentet for overvåking som tester reell levering, framfor å stole på applikasjonens egen framstilling av seg selv.

Feil nummer to var også et personvernspørsmål. Interne data om en henvendelse som havner hos den besøkende selv, er ikke bare rot i koden. Går personopplysninger til feil mottaker, må virksomheten vurdere det opp mot pliktene sine, og den vurderingen blir langt enklere hvis loggene faktisk sier hva som ble sendt og til hvem.

Dette var en egenutviklet PHP-applikasjon, men den samme fellen ligger og venter i de fleste WordPress-nettsteder. WordPress sender gjennom PHPMailer, og med mindre SMTP er satt opp bevisst, faller det tilbake til den samme mail()-transporten med den samme blindsonen. Et kontaktskjema som melder suksess mens ingenting kommer fram, ser identisk ut på begge stakker. Det er en av grunnene til at levering fra skjemaer er verdt å teste som del av vanlig vedlikehold framfor å anta at det virker.

Det samme gjelder ordrebekreftelser og varsler fra WooCommerce. En butikk kan miste både ordrevarslene til seg selv og bekreftelsene til kunden uten at noe sted sier fra, og de tapte bekreftelsene dukker opp igjen som supporthenvendelser noen dager senere.


Sender kontaktskjemaet ditt egentlig e-post?

Har henvendelsene blitt stille, eller er du usikker på om e-postene fra skjemaet faktisk kommer fram, kan vi spore den reelle leveringsveien og flytte deg over på autentisert utsending som rapporterer ærlig når noe feiler. Send oss detaljene, så finner vi ut om skjemaet ditt leverer eller bare påstår at det gjør det.

Chat på WhatsApp