Page 1 of 1

php mail sends the mail but body is not visiable

Posted: Thu Mar 15, 2007 1:43 pm
by collette
Below is the source of an email, the way mozilla mail shows it. But the body of the mail is not visiable in the normal way. So, if I start mozilla mail and check for new mail, I see the header and below that its blank. Only when I click "view source" I get this:

Code: Select all

From - Thu Mar 15 19:18:14 2007
X-UIDL: 1173982686._smtp.mxdrop29.16846,S=3017
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
Return-Path: <anonymous@somedomain>
Received: from ns1.somedomain(
Received: (qmail 387 invoked by uid 48); 15 Mar 2007 19:18:04 +0100
Date: 15 Mar 2007 19:18:04 +0100
Message-ID: <20070315181804.386.qmail@somedomain>
To: colweb@xs4all.nl
Subject: Test HTML email
From: website@mydomain
Reply-To: webmaster@mydomain
Content-Type: multipart/alternative; boundary="PHP-alt-9b219c8fff7fe3cfea4f4a8b88470cb6"
X-XS4ALL-DNSBL-Checked: mxdrop29.xs4all.nl checked 62.148.174.180 against DNS blacklists
X-Virus-Scanned: by XS4ALL Virus Scanner
X-XS4ALL-Spam-Score: 0.6 () DK_POLICY_SIGNSOME,HTML_MESSAGE,MIME_HEADER_CTYPE_ONLY,NO_REAL_NAME
X-XS4ALL-Spam: NO
Envelope-To: colweb@xs4all.nl
X-UIDL: 1173982686._smtp.mxdrop29.16846,S=3017

--PHP-alt-9b219c8fff7fe3cfea4f4a8b88470cb6 

Content-Type: text/plain; charset=iso-8859-1

Content-Transfer-Encoding: 8bit

Bestelling VVV Actief Gids en/of Kaart.

Uw naam: 

Adres: 

Postcode: 

Plaats: 

e-mail adres: 



VVV Actief gids, aantal: 1 - prijs: 1.00

VVV Actief kaart, aantal: 1 - prijs: 1.00

Sub totaal.........................: 2.00

Korting............................: 0.50

Verzend en administratie kosten....: 2.50

Totaal.............................: 4.00



Bedankt voor uw bestelling. Levertijd is circa 2 werkdagen.

--PHP-alt-9b219c8fff7fe3cfea4f4a8b88470cb6 

Content-Type: text/html; charset=iso-8859-1

Content-Transfer-Encoding: 8bit

<html>

<head></head>

<body>

<table border="1" cellpadding="3" cellspacing="3">

    <tr><td colspan="5"><center>Bestelling VVV Actief Gids en/of Kaart</center></td></tr>

    <tr><td rowspan="8" style="vertical-align: top;">

        <table border="0" cellpadding="0" cellspacing="3">

            <tr><td>Uw naam:</td><td></td></tr>

            <tr><td>Adres:</td><td></td></tr>

            <tr><td>Postcode:</td><td></td></tr>

            <tr><td>Plaats:</td><td></td></tr>

            <tr><td>e-mail adres:</td><td></td></tr>

        </table>

    </td></tr>

    <tr><th>Produkt</th><th>Prijs</th><th>Aantal</th><th>Totaal</th></tr>

    <tr><td>VVV Actief gids</td><td>&euro; 1,00 </td><td>1</td><td>1.00</td></tr>

    <tr><td>VVV Actief kaart</td><td>&euro; 1,00 </td><td>1</td><td>1.00</td></tr>

    <tr><td colspan="3" align="right">Sub totaal: &euro;&nbsp;</td><td>2.00</td></tr>

    <tr><td colspan="3" align="right">Korting: &euro;&nbsp;</td><td>0.50</td></tr>

    <tr><td colspan="3" align="right">Verzend en administratie kosten: &euro;&nbsp;</td><td>2.50</td></tr>

    <tr><td colspan="3" align="right">Totaal: &euro;&nbsp;</td><td>4.00</td></tr>

    <tr><td colspan="5" align="center">Bedankt voor uw bestelling. Levertijd is circa 2 werkdagen.</td></tr>

</table>

</body>

</html>

--PHP-alt-9b219c8fff7fe3cfea4f4a8b88470cb6--


--PHP-alt-9b219c8fff7fe3cfea4f4a8b88470cb6--
The code to produce this mail is:

Code: Select all

<?php
$naam = $_POST['naam'];
$adres = $_POST['adres'];
$pcode = $_POST['pcode'];
$plaats = $_POST['plaats'];
$email = $_POST['email'];
$gids_aantal = $_POST['gids_aantal'];
$gids_totaal = $_POST['gids_totaal'];
$kaart_aantal = $_POST['kaart_aantal'];
$kaart_totaal = $_POST['kaart_totaal'];
$sub_tot = $_POST['sub_tot'];
$korting = $_POST['korting'];
$verzend = $_POST['verzend'];
$totaal = $_POST['totaal'];
//define the receiver of the email
$to = 'colweb@xs4all.nl';
//define the subject of the email
$subject = 'Test HTML email';
//create a boundary string. It must be unique
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time()));
//define the headers we want passed. Note that they are separated with \r\n
$headers = "From: website@mydomain\r\nReply-To: webmaster@mydomain";
//add boundary string and mime type specification
$headers .= "\r\nContent-Type: multipart/alternative; boundary=\"PHP-alt-".$random_hash."\"";
//define the body of the message.
ob_start(); //Turn on output buffering
?>
--PHP-alt-<?php echo $random_hash; ?> 
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
Bestelling VVV Actief Gids en/of Kaart.

Uw naam: <?php echo "$naam\r\n"; ?>
Adres: <?php echo "$adres\r\n"; ?>
Postcode: <?php echo "$pcode\r\n"; ?>
Plaats: <?php echo "$plaats\r\n"; ?>
e-mail adres: <?php echo "$email\r\n"; ?>

VVV Actief gids, aantal: <?php echo $gids_aantal; ?> - prijs: <?php echo "$gids_totaal\r\n"; ?>
VVV Actief kaart, aantal: <?php echo $kaart_aantal; ?> - prijs: <?php echo "$kaart_totaal\r\n"; ?>
Sub totaal.........................: <?php echo "$sub_tot\r\n"; ?>
Korting............................: <?php echo "$korting\r\n"; ?>
Verzend en administratie kosten....: <?php echo "$verzend\r\n" ?>
Totaal.............................: <?php echo "$totaal\r\n" ?>

Bedankt voor uw bestelling. Levertijd is circa 2 werkdagen.
--PHP-alt-<?php echo $random_hash; ?> 
Content-Type: text/html; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
<html>
<head></head>
<body>
<table border="1" cellpadding="3" cellspacing="3">
    <tr><td colspan="5"><center>Bestelling VVV Actief Gids en/of Kaart</center></td></tr>
    <tr><td rowspan="8" style="vertical-align: top;">
        <table border="0" cellpadding="0" cellspacing="3">
            <tr><td>Uw naam:</td><td><?php echo $naam; ?></td></tr>
            <tr><td>Adres:</td><td><?php echo$adres; ?></td></tr>
            <tr><td>Postcode:</td><td><?php echo $pcode; ?></td></tr>
            <tr><td>Plaats:</td><td><?php echo $plaats; ?></td></tr>
            <tr><td>e-mail adres:</td><td><?php echo $email; ?></td></tr>
        </table>
    </td></tr>
    <tr><th>Produkt</th><th>Prijs</th><th>Aantal</th><th>Totaal</th></tr>
    <tr><td>VVV Actief gids</td><td>&euro; 1,00 </td><td><?php echo $gids_aantal; ?></td><td><?php echo $gids_totaal; ?></td></tr>
    <tr><td>VVV Actief kaart</td><td>&euro; 1,00 </td><td><?php echo $kaart_aantal; ?></td><td><?php echo $kaart_totaal ?></td></tr>
    <tr><td colspan="3" align="right">Sub totaal: &euro;&nbsp;</td><td><?php echo $sub_tot; ?></td></tr>
    <tr><td colspan="3" align="right">Korting: &euro;&nbsp;</td><td><?php echo $korting ?></td></tr>
    <tr><td colspan="3" align="right">Verzend en administratie kosten: &euro;&nbsp;</td><td><?php echo $verzend; ?></td></tr>
    <tr><td colspan="3" align="right">Totaal: &euro;&nbsp;</td><td><?php echo $totaal; ?></td></tr>
    <tr><td colspan="5" align="center">Bedankt voor uw bestelling. Levertijd is circa 2 werkdagen.</td></tr>
</table>
</body>
</html>
--PHP-alt-<?php echo $random_hash; ?>--
<?
//copy current buffer contents into $message variable and delete current output buffer
$message = ob_get_clean();
//send the email
$mail_sent = @mail( $to, $subject, $message, $headers );
//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed" 
echo $mail_sent ? "Mail sent" : "Mail failed";
?>
The mail source and php code contain 'mydomain' and 'somedomain'. In real the right domain names are filled in here.

Things become even stranger when I use my ISP webmail service. Then the mail body is shown. Can somebody point out what is going wrong here?

Thanks.

Posted: Thu Mar 15, 2007 4:01 pm
by Chris Corbyn
If your server runs linux you need to use \n not \r\n.

Posted: Thu Mar 15, 2007 4:27 pm
by collette
The server indeed runs linux. But changing \r\n to only \n does not solve anything. The reason to use \r\n is because most users will be using a mail client in windows. Linux mail clients seem to know what to do with \r\n but windows clients don't understand \n only. They need \r\n.

Posted: Fri Mar 16, 2007 11:10 am
by abeterosso
//create a boundary string. It must be unique
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time()));

Hi, I'm new to php. Can you explain me this part of your code? Why do you need a random number? Thanks

Posted: Fri Mar 16, 2007 12:24 pm
by collette
Because the email contains both text and html it is a Mime type mail. Mime is specified in these RFC's : 2045, 2046, 2047, 2048 and 2077. But that is not what you were asking.....
It is up to the sending mail client to choose a boundary string that doesn't clash with the body text. Typically this is done by inserting a large random string.
Don't remember where I found this, but I always use some form of random to create the mime boundary. It is possible (or at least it was possible) with uuencoded messages to have a boundary that is the same as some part of the uuencoded stuff. At least at one occasion it happened to me. That was years ago, before I used this random boundary method.

Posted: Sat Mar 17, 2007 4:23 am
by abeterosso
...thank you very much!
your answer is very useful for me 'cause I'm developing an application where a confirmation by email is due...

Posted: Sat Mar 17, 2007 7:00 am
by Chris Corbyn
collette wrote:The server indeed runs linux. But changing \r\n to only \n does not solve anything. The reason to use \r\n is because most users will be using a mail client in windows. Linux mail clients seem to know what to do with \r\n but windows clients don't understand \n only. They need \r\n.
Yep, well this is why mail() sucks. Even the manual says to try \n if \r\n is giving double lines but the fact is, you need to do this:

Code: Select all

if (substr(PHP_OS, 0, 3) != "WIN"))
{
    //use \n
}
else
{
    //use \r\n
}

Posted: Sat Mar 17, 2007 6:44 pm
by collette
Have changed \r\n in \n but that does not solve it.

After removing the text part (and boundary stuff), the remaining html mail is visiable in mozilla mail. Same goes for removing the html part and only leave the text part in. It has to be something with the header or mime boundary wy mozilla mail won't show the body.

Have written some php mail scripts before but can't find out what I'm doing wrong here. Anybody?

Posted: Sat Mar 17, 2007 6:48 pm
by John Cartwright
d11wtq wrote:
collette wrote:The server indeed runs linux. But changing \r\n to only \n does not solve anything. The reason to use \r\n is because most users will be using a mail client in windows. Linux mail clients seem to know what to do with \r\n but windows clients don't understand \n only. They need \r\n.
Yep, well this is why mail() sucks. Even the manual says to try \n if \r\n is giving double lines but the fact is, you need to do this:

Code: Select all

if (substr(PHP_OS, 0, 3) != "WIN"))
{
    //use \n
}
else
{
    //use \r\n
}
Why not use PHP_EOL constant instead?

Posted: Sun Mar 18, 2007 6:10 am
by Chris Corbyn
I was about to say because I didn't kno it existed. But it won't work on a Mac because EOL is \r in that case.

Posted: Sun Mar 18, 2007 6:11 am
by Chris Corbyn
collette wrote:Have changed \r\n in \n but that does not solve it.

After removing the text part (and boundary stuff), the remaining html mail is visiable in mozilla mail. Same goes for removing the html part and only leave the text part in. It has to be something with the header or mime boundary wy mozilla mail won't show the body.

Have written some php mail scripts before but can't find out what I'm doing wrong here. Anybody?
Sory, but I have to ask, have you looked at Swift Mailer?

http://www.swiftmailer.org/

You'd probably have this working in 10 mins if you did ;)

EDIT | Your ob_start() could be causing issues with the LE if you're sending via SMTP in which case you'll need to run some LE fixes on the string.

EDIT 2 | Upon closer inspection of your message body you have numerous issues that are going to prevent your mail from working with various clients. The big one... you have no blank line after any of your headers.

Posted: Sun Mar 18, 2007 8:14 am
by collette
Sory, but I have to ask, have you looked at Swift Mailer?
Just looked at it. Don't have time today to test and see what it will do for me, but will do so tomorrow. Looks like it will do what I need.
EDIT | Your ob_start() could be causing issues with the LE if you're sending via SMTP in which case you'll need to run some LE fixes on the string.

EDIT 2 | Upon closer inspection of your message body you have numerous issues that are going to prevent your mail from working with various clients. The big one... you have no blank line after any of your headers
What kind of fixes on the string are needed? When I remove the html part and still use ob_start() , the text message is shown in mozilla mail. Same goes for the header.

Posted: Sun Mar 18, 2007 8:27 am
by Chris Corbyn
I'm inclined to think the issues is temming from the lack of CRLF CRLF between then headers and the mime parts.

However, here's the way I correct EOL:

Code: Select all

/**
 * Fixes line endings to be whatever is specified by the user
  * SMTP requires the CRLF be used, but using sendmail in -t mode uses LF
  * This method also escapes dots on a start of line to avoid injection
  * @param string The data to fix
  * @return string
  */
  protected function fixLE($data, $le)
  {
      $data = str_replace(array("\r\n", "\r"), "\n", $data);
      if ($le != "\n") $data = str_replace("\n", $le, $data);
      return $data = str_replace($le . ".", $le . "..", $data);
  }
http://swiftmailer.svn.sourceforge.net/ ... iew=markup

Posted: Thu Mar 22, 2007 8:55 am
by collette
Sorry for the late reaction. Have changed so much to the original code that it isn't original code anymore. But it finally works.

The most important thing had to do with "\r\n" or "\n". So I included this code:

Code: Select all

// Is the OS Windows or Mac or Linux
if (strtoupper(substr(PHP_OS,0,3)=='WIN')) {
  $eol="\r\n";
} elseif (strtoupper(substr(PHP_OS,0,3)=='MAC')) {
  $eol="\r";
} else {
  $eol="\n";
}
I found this code on an other website dealing with sending mail with php. And inside the rest of the code changed "\r\n" and "\n" to .$eol;

So, for instance this line:

Code: Select all

$headers = "From: website@mydomain\r\nReply-To: webmaster@mydomain";
became:

Code: Select all

$headers = "From: website@mydomain".$eol;
$headers .= "Reply-To: webmaster@mydomain".$eol;
d11wtq was right about the hole end of line thing. Therefore thanks d11wtq. It took me some time to see what en where I had to make changes. If you wish to see the final code, please let me know.

You can see the form in action on http://www.vvv-wymbrits.nl (press the button: bestellen in the right column).