I have a strange problem with the PHP mail(); function.
Using it like this
$header = "MIME-Version: 1.0" . "\r\n";
$header .= "Content-type: text/html; charset=utf-8" . "\r\n";
$header .= "Content-Transfer-Encoding: quoted-printable" . "\r\n";
$header .= "Reply-To:" . $email . "\r\n";
$header .= "From: Kontaktformular <noreply#thomas-glaser-foto.de>" . "\r\n";
mail( "mail.me#mail.com", "Message from " . $name . " through your website!", $message, $header );
everything works as expected. The mail gets send, everything is encoded correctly and the subject is also ok.
But when I change the double quotes with single quotes like this:
$header = 'MIME-Version: 1.0' . '\r\n';
$header .= 'Content-type: text/html; charset=utf-8' . '\r\n';
$header .= 'Content-Transfer-Encoding: quoted-printable' . '\r\n';
$header .= 'Reply-To:' . $email . '\r\n';
$header .= 'From: Kontaktformular <noreply#thomas-glaser-foto.de>' . '\r\n';
mail( 'mail.me#mail.com', 'Message from ' . $name . ' through your website!', $message, $header );
The mail still gets send, but without the set subject. Instead, it is
www-data#domain.com
and the special characters are also destroyed. What is happening there?
Single quotes are for literal strings, no variables are replaced/expanded, and no escape sequences other than \' and \\ are respected. The way you've written your code you can leave the single-quotes as-is except you must have the line breaks double quoted as "\r\n".
Double quotes are needed to put in the special linebreak characters ("\r\n"). They are not treated as linebreaks when you use single quotes, instead they will be treated as literal text.
The PHP interpreter will evaluate material in double quotes, but it doesn't do so to single quotes. Because of this, the best practice is to only use double quotes when something needs to be evaluated (like a variable, when concatenation isn't possible, or special characters like line breaks).
Please read the manual:
http://php.net/manual/en/language.types.string.php
Single quoted
To specify a literal single quote, escape it with a backslash (). To
specify a literal backslash, double it (\). All other instances of
backslash will be treated as a literal backslash: this means that the
other escape sequences you might be used to, such as \r or \n, will be
output literally as specified rather than having any special meaning.
Related
I'm having an issue getting the line folding to work the way it's specified. I'm obviously misunderstanding something about the documentation, so I was hoping I could get some help. The validator at https://icalendar.org/validator.html is saying
Lines not delimited by CRLF sequence near line # 1
Reference: RFC 5545 3.1. Content Lines
This is my function to generate the .ics files for download:
public function getCalendarFile($event) {
header("Content-Type: text/Calendar; charset=utf-8");
header("Content-Disposition: attachment; filename="ExampleFile.ics");
$icsFile = "BEGIN:VCALENDAR\r\n";
$icsFile .= "VERSION:2.0\r\n";
$icsFile .= "PRODID:Example Event" . $event->name . "\r\n";
$icsFile .= "METHOD:PUBLISH\r\n";
$icsFile .= "BEGIN:VEVENT\r\n";
$icsFile .= "UID:". $event->name . gmdate("Ymd\THis\Z", strtotime(Carbon::now())) . "\r\n";
$icsFile .= "DTSTAMP:" . gmdate("Ymd\THis\Z", strtotime(Carbon::now())) . "\r\n";
$icsFile .= "DTSTART:" . gmdate("Ymd\THis\Z", strtotime($event->begin)) . "\r\n";
$icsFile .= "DTEND:" . gmdate("Ymd\THis\Z", strtotime($event->end)) . "\r\n";
$icsFile .= "LOCATION:" . strip_tags($event->location) . "\r\n";
$icsFile .= "SUMMARY:" . $event->name . "\r\n";
$icsFile .= "DESCRIPTION:" . $this->foldCalendarDescription(strip_tags($event->description)) . "\r\n";
$icsFile .= "END:VEVENT\r\n";
$icsFile .= "END:VCALENDAR\r\n";
echo $icsFile;
}
public function foldCalendarDescription($description) {
return wordwrap($description, 75, "\r\n\t", TRUE);
}
I'm not sure if it has something to do with strip_tags possibly? The event description is stored as a wysiwyg html input. But the issue says with line # 1 and line # 1 looks fine to me.
Here's a wrapper for ICAL strings that works for me:
function format_ical_string( $s ) {
$r = wordwrap(
preg_replace(
array( '/,/', '/;/', '/[\r\n]/' ),
array( '\,', '\;', '\n' ),
$s
), 73, "\n", TRUE
);
// Indent all lines but first:
$r = preg_replace( '/\n/', "\n ", $r );
return $r;
}
As I wrote in the comment beneath kmoser's answer, people seem to be really hard pressed to get exactly 75 bytes on a line and create very convoluted code to do that. But why not just sometimes less than 75 bytes? A simple wordwrap will give you that because it just looks for whitespace to break and is not multi-byte aware. You'll possibly have a few more linebreaks in the iCal object code than strictly neccessary, but does that matter? This is why I upvoted kmoser's answer. It's a nice and simple solution.
I've tried to create an even simpler and faster version of kmoser's answer:
function format_ical_string( $str ) {
$str = str_replace(
[ "\r\n", '\\', ',', ';', "\n" ], // replacement order is important
[ "\n", '\\\\', '\,', '\;', '\n' ], $str );
return wordwrap( $str, 73, "\n ", false );
}
The replacements (just a str_replace, because nothing fancy is needed here) are:
replace CRLF's with just LF's
replace literal backslashes with escaped backslashes
escape comma's
escape semicolons
replace newlines with a literal \n (per rfc5545)
Then wordwrap with a LF + space (per rfc5545).
After this, strictly you should replace all LF's with CRLF's (rfc5545 line ending). I tend to format the entire iCal object with just LF's, and only at the very end replace all LF's with CRLF's to make the result compliant. This saves me the hassle of repeatedly inserting these Windows line endings (who uses those these days?) during the composition of my iCal objects.
It is unclear from rfc5545 if the property name itself is counted in the 75 bytes line limit, as in https://www.rfc-editor.org/rfc/rfc5545#section-3.1:
Lines of text SHOULD NOT be longer than 75 octets, excluding the line break.
But just to be sure, I feed the property name to the function, as in:
$line = format_ical_string( 'SUMMARY:Really long text here' );
IMPORTANT: my function above will fail on single words (!) that are longer than 75 bytes. I'm not sure how common that is. If you have an 18-character word completely made of 4-byte characters, you'd be at the limit. This seems very unlikely to me.
I'd like to send email using mail function.
Want to add line breaks as follows.
$msg = 'aaaaa'.'\r\n'.'bbbbbb'.'\r\n';
$headers .= "Content-Type: text/plain; charset=\"utf-8\"\r\n";
$to = 'test#test.com';
mail($to,'Subject',$msg,$headers);
But not working.
How can I send email as follows.
aaaaa
bbbbbb
New line is "\n", not '\n' (double quotes instead of single-quotes).
$msg = 'aaaaa'."\n".'bbbbbb'."\n";
Explanation is here:
http://php.net/manual/en/language.types.string.php#language.types.string.syntax.double
If the string is enclosed in double-quotes ("), PHP will interpret more escape sequences for special characters
To add line break you need to add "\n", not '\n'
You may use html tags in your mail body like this(<br /> breaks to new-line) :
$message = '<html><body>';
$message .= '<h1>Hello, World!</h1><p>Hello<br />This is in a newline</p>';
$message .= '</body></html>';
If you want to send plain text then you may just use \n.
In your case :
$msg = "aaaaa \r\n bbbbbb \r\n";
And your headers :
$headers = "From: Name <info#name.com> \r\n";
$headers .= "MIME-Version: 1.0 \r\n";
$headers .= "Content-Type: text/html; charset=UTF-8 \r\n";
Note: In case of single quoted string,
To specify a literal backslash, double it (\). All other instances of
backslash will be treated as a literal backslash: this means that the
other escape sequences you might be used to, such as \r or \n, will be
output literally as specified rather than having any special meaning.
I'm not sure what I am doing wrong here. In the emails, \r\n keeps showing every time there is a line break. What do I need to modify in this code to fix it.
public function sendSupportEmail($email, $name, $comments)
{
//Wait until Google Apps are configured to accept from this domain
//$to = "test#mail.com";
$to = "test#mail.com.com";
$subject = "Support: Support Inquiry";
//Headers
// To send HTML mail, you can set the Content-type header.
$autoHeaders = "MIME-Version: 1.0\r\n";
$autoHeaders .= "Content-type: text/html; charset=iso-88591\r\n";
$autoHeaders .= "From: Web Bot";
$autoHeaders .= "<webbot#mail.com>\r\n";
$autoHeaders .= "Reply-To: webbot#mail.com\r\n";
$autoHeaders .= "Return-Path: webbot#mail.com\r\n";
$autoHeaders .= "X-Mailer: PHP 5.x\r\n";
//Print the local date
$date = new DateTime('now', new DateTimeZone('America/Denver'));
$datePrint = $date->format('F j, Y, g:i a');
//Create Text Based Message Below
$message = "<h3>Support Inquiry sent on {$datePrint}</h3>";
$message .= "<b>Name:</b><br>{$name}<br><br>";
$message .= "<b>Email:</b><br><a href='mailto:{$email}'>{$name}</a><br><br>";
$message .= "<b>Comments:</b><p>{$comments}</p>";
//Send them the E-Mail
return mail($to, $subject, $message, $autoHeaders);
}
I had same issue, turns out using mysqli_real_escape_string was causing it.
For the headers ($autoHeaders), \r\n is the correct way to separate various fields. But the $comments itself needs to use the HTML <br>-tag to denote a line-break, because you're sending a HTML e-mail (see Content-Type).
You can use the nl2br function for that:
$message = "<h3>Support Inquiry sent on {$datePrint}</h3>";
$message .= "<b>Name:</b><br>{$name}<br><br>";
$message .= "<b>Email:</b><br><a href='mailto:{$email}'>{$name}</a><br><br>";
$message .= "<b>Comments:</b><p>{" . nl2br($comments) . "}</p>";
return mail($to, $subject, $message, $autoHeaders);
In addition you can use htmlentities() on $comments before nl2br to convert other characters to HTML entities (like € for € f.e.):
$message = "<h3>Support Inquiry sent on {$datePrint}</h3>";
$message .= "<b>Name:</b><br>{$name}<br><br>";
$message .= "<b>Email:</b><br><a href='mailto:{$email}'>{$name}</a><br><br>";
$message .= "<b>Comments:</b><p>{" . nl2br(htmlentities($comments)) . "}</p>";
return mail($to, $subject, $message, $autoHeaders);
See Ideone sample
\n\r codes are going to be invisible in an Email client, regardless of whether or not you are rendering HTML or Text-based email. Look at, for instance, the Source Code of this website, and that of Google. Anything that is on a new line, technically, has a \n\r at the end.
\n\r says, to the text renderer "Line-Feed, Carriage Return," which harks back to terminals, and essentially says "Cursor down, Return cursor to start of line," much like on a typewriter.
In straight Text documents, this behaves as you would expect. However, as HTML is a markup-language, there are language codes that do this instead, and inner line-feeds have no effect.
I say all of the above to point out one specific thing: If there are ACTUAL line-feeds and carriage returns in your HTML document, you would not see them, as they are not the actual text '\n\r', \n and \r are textual representations of control characters.
So, all of that said, why would you see these? If you actually had the text '\n\r' in the document, and not the control characters. This can happen a few ways, most notably, misunderstanding the difference between " and '. " interprets the text inside of it, expanding control characters, variable references, etc, while ' does not:
$foo = 'bar';
echo "$foo"; // 'bar'
echo '$foo'; // '$foo'
echo "\n"; // actual line-feed
echo '\n'; // the text '\n'
See here for an example.
It is my guess that the actual contents of $comments contains the actual text '\n\r' and not the Line-feed + Carriage Return control characters. Either the user is actually entering the characters '\n\r' or you are inserting them somewhere. Look in your code and be sure you are using double-quotes anywhere you are trying to use control characters.
While I suggest cleaning your code to ensure that you are not inserting the text "\n\r" yourself, if it is actually the USER inserting these characters, you can clean them using this method.
I'm using the PHP Mail function to send an email and the message has several lines which I've delimited with \r\n, however when the email arrives it contains \r\n in the message instead of starting each row on a new line.
$subject = 'Activation';
$message = 'ActivationCode=' . $activationcode . '\r\nUserLimit=' . $row['userlimit'] . '\r\nCanNetwork=' . $row['canrunonnetwork'];
$headers = 'From: noreply#here.com';
mail('me#here.com', $subject, $message, $headers);
When the email arrives it looks like this:
ActivationCode=1234\r\nUserLimit=4\r\nCanNetwork=-1
whereas I'd expected it to look like this:
ActivationCode=1234
UserLimit=4
CanNetwork=-1
Change your string delimiter to double quotes.
In PHP strings delimited with ' are literal, strings delimited with " are interpreted.
So these are equal:
'\r\n' === "\\r\\n"; // true
You should use double (") quotes instead if single ones. Variables and line endings etc. don't get expanded in single quotes.
So you code should be:
message = "ActivationCode=" . $activationcode . "\r\nUserLimit= ...etc.";
I sending a message with this code below and works:
$headers = 'From: Online <'.$emailTo.'>\r\n';
$headers .= 'Reply-To: '.$emailTo.'\r\n';
$headers .= 'Return-Path: Online <'.$emailTo.'>\r\n';
$headers .= "Bcc: email#hotmail.com\r\n";
$headers .= "Bcc: email#gmail.com\r\n";
The problem is When I click in Reply on the email appear like this in the field to:
Online \r\nReply-To: email#server.com.au\r\nReturn-Path: Online \r\nBcc: email#hotmail.com
Any idea that can help me?
Cheers M
\r and \n must be enclosed in double quotes, in single quoted strings they are taken literally.