Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP mail function randomly adds a space to message text

I have a very simple PHP script, something like:

while ($condition){
    echo "<a href="thanks.php?id=".$id."> THANKS </a>";
}

Of course, I have a bit more code but it doesn't matter. Once I had created this piece of code, the script sends an email to the user.

THE INBOX

The links are okay in every single line, except the LAST ONE shows the link this way:

    tha nks.php?id.....

It adds a space in between the code.

This only happens with hotmail. Gmail, yahoo, and everything else work just fine.

like image 728
Andy Avatar asked Apr 03 '12 19:04

Andy


6 Answers

I know this is late but there is an alternate solution that worked for me:

Use this line to encode your entire message using base64:

$message = chunk_split(base64_encode($message));

Then, append this your header:

$headers .= "Content-Transfer-Encoding: base64\r\n\r\n";

That will tell the mail client that your message is base64 encoded.

like image 200
karancan Avatar answered Nov 12 '22 03:11

karancan


karancan's solution should work, but the root cause is what Hobo was saying. The SMTP protocol requires that lines be limited to 1000 characters (or really 998 characters plus a CR-LF). If your line is longer than 1000 characters, a CR-LF will be inserted every 998 characters.

So if you're building up your $message with a bunch of $message .= "more text"; you'll encounter this error once that line is greater than 900 characters long. It's confusing though because the spaces seem to be intermittent, particularly if you're building up an HTML message because sometimes the linebreaks will appear in perfectly benign locations.

The simple solution is to add a \r\n\ to the end of lines.

Interestingly, these forms work:

$message .= "<tr><td>1</td><td>2</td>\r\n";
$message .= '<tr><td>1</td><td>2</td>'."\r\n";

But this does not:

$message .= '<tr><td>1</td><td>2</td>\r\n';

The \r\n must be surrounded by double quotes, otherwise the characters will just get added to the text instead of creating a carriage return/line break.

@karancan is correct though, and you can skip adding the \r\n's if you base64 encode your messages, and add the required header.

like image 33
Mordred Avatar answered Nov 12 '22 03:11

Mordred


Was facing the same problem and tried most of these solutions but it did not work for me. It seems when the line seems too long to mail function it adds space around 900 character mark. So the following solution of adding wordwrap worked for me.

mail($to, $subject, wordwrap($message), $headers);

like image 14
Pranjal Avatar answered Nov 12 '22 02:11

Pranjal


I've seen sendmail insert characters when lines are too long. That's not the case here (as other clients are handling it fine), but I wonder if hotmail has a line length limit that you're hitting.

Does it make any difference if you insert a newline in your echo, ie

while ($condition){

    echo "<a href=\"thanks.php?id=".$id."\"> THANKS </a>\n";

}
like image 2
Hobo Avatar answered Nov 12 '22 02:11

Hobo


2019 working answer

The SMTP protocol requires a CRLF after each line which contains more than 998 characters. Basically each line of 1000 must contain at its very end the CRLF characters.

The simplest working solution to this issue is to send the email content encoded in base64 then add a header that tells mail clients that the content was encoded in base 64 and then send the email.

Bellow is an working example. I've tested with a mail which had ~ 27000 chars and it worked perfectly. Before this update, it was breaking critical links in my HTML content.

<?php

// used for date() function
date_default_timezone_set('Europe/Bucharest');


$to = '[email protected]';
$from = '[email protected]';
$fromName = 'John Doe';

$subject = "Html email test at ".date('H:i:s');


// Set content-type header for sending HTML email
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
$headers .= "Content-Transfer-Encoding: base64" . "\r\n";


// Additional headers
$headers .= 'From: '.$fromName.'<'.$from.'>' . "\r\n";
$headers .= 'Cc: [email protected]' . "\r\n";
$headers .= 'Bcc: [email protected]' . "\r\n";


$extremely_long_html_email = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
<html xmlns=\"http://www.w3.org/1999/xhtml\">
<head>
    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"/>
    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>
    <title>TEST</title>
    </head>
    <body>
        Very long HTML code. I stripped mine due to copyright issues.
    </body>
</html>";


// Send email
if(mail($to, $subject, base64_encode($extremely_long_html_email), $headers)){
    echo 'Email has sent successfully.';
}else{
    echo 'Email sending failed.';
}
?>

TL;DR; Add extra headers $headers .= "Content-Transfer-Encoding: base64" . "\r\n"; and encode html content before sending it using base64_encode($html_email) function.

like image 2
besciualex Avatar answered Nov 12 '22 01:11

besciualex


If you are using PHPMailer, or Joomla CMS (which uses PHPMailer), the appropriate code to use utf-8 and base64 encode your message (the equivalent of karancan's solution) is:

$mailer->CharSet = 'utf-8';
$mailer->Encoding = 'base64'

Note that you should not chunk_split(base64_encode($emailBody)); because PHPMailer automatically does this for you as soon as you set Encoding to base64, and you do not want to have your email body base64 encoded twice :)

like image 1
Gavin G Avatar answered Nov 12 '22 03:11

Gavin G