Line break in body of mailto: link
Asked Answered
L

8

8

I want to create a “Forward this to a friend” link below a blog post that opens my email client with a prepared message. I can get it to work for a single-line message, but I’d like to be able to break lines inside the message body. How can I do that?

<?php
printf(
    '<a href="mailto:?subject=%s&body=%s">Forward this to a friend</a>',
    the_title_attribute('echo=0'),
    sprintf('The link: %s Have a great day! Stefaan', get_the_permalink())
);
?>

How do I start “Have a great day!” on a new line with an empty line above?

The link: ...

Have a great day!

Stefaan

My blog uses WordPress with a Genesis theme and I put my code into the genesis_footer_entry hook with PHP enabled (see screenshot – email text is in Dutch).

Leisure answered 30/5, 2016 at 11:34 Comment(2)
Sidenote: Should consider encoding the ampersand: mailto:?subject=%s&amp;body=%sDurable
I believe the problem is on your blog CMS. Can you give more details on how this link is being generated?Idolize
M
4

You cannot use HTML tags in body of mailto

According to RFC 2368, this is not possible:

The special hname "body" indicates that the associated hvalue is the body of the message. The "body" hname should contain the content for the first text/plain body part of the message. The mailto URL is primarily intended for generation of short text messages that are actually the content of automatic processing (such as "subscribe" messages for mailing lists), not general MIME bodies.

So any solution depends on HTML tags is not possible. The solution I'm suggesting is to use \r\n along with PHP function rawurlencode

So here's the code

<?php

     printf( 
    '<a class="simple-mail-link" href="mailto:[email protected]?subject=%s&body=%s"><div class="label"><div class="dashicons dashicons-admin-plugins"></div>Forward this to a friend</div></a>', 
    'My Subject',
    rawurlencode(sprintf( "Hi there, this might be interesting for you.\r\nThis is the link: %s.\r\nHave a great day!\r\nStefaan", get_the_permalink()))
    );

?>

Note: I tried the code with replacing get_the_permalink() with variable carrying http://example.com/test.php

references:

MailTo with HTML body

What is the equivalent of JavaScript's encodeURIcomponent in PHP?

Mauriac answered 15/6, 2016 at 1:5 Comment(4)
Your solution worked, thank you! But since SML was the first to post this solution, I awarded him the bounty. Hope you understand ; )Leisure
I agree, actually I read his solution after I wrote my solution, but it's fine with me. thank you :)Mauriac
I tried a lot of things before this worked for me. Thank youRozella
Welcome, happy to help :)Mauriac
C
3

Explanation

a mailto: is a URI scheme for email address, like all other URIs, characters need to be translated into a format that can be transmitted over the Internet.

Take a simplified form of your original code to illustrate the points below

printf(<href="mailto:?subject=%s&body=%s">Description</a>, the_title_attribute( 'echo=0' ) , sprintf("content link:%s more content", get_the_permalink())

The code runs in the following sequences

  1. get_the_permalink() gets the URL of your page
  2. sprintf() replaces %s in $content with the result of step 1
  3. print_f() then replaces
    i) the first %s i.e. subject=%s with the fetched result of the_title_attribute( 'echo=0' ), which I assume is the title of the page or your site and then ii) the second %s i.e. body=%s with the result of step 2 to form a complete a mailto link

In order to retain the line breaks, you should convert the $content string into URL encoded form before outputting it.

In PHP that's done by using the rawurlencode() function, it translates line breaks \r\n in string into %0D%0A, as per RFC 3986.

Since the percentage sign % is used for conversion specification in sprint_f(), you should pass the string to rawurlencode() after the string has been formatted by sprint_f(), therefore the use of rawurlencode(sprint_f($string, $arg))


Solution
I have put together the solution in full for you to copy and paste into your widget to avoid false negative due to wrongful implementation.

Format 1 and format 2 contain essentially the same code, the two formats are there to illustrate to you how you can insert line break, either by 1) pressing enter OR 2) by typing in \r\n where line break is needed.

I have made $content a separate string for your ease of editing and readability of code.

Format 1

 <?php
  //Start new line by pressing enter
  //IMPORTANT NOTE: do not remove the %s 
    $content="Hi there, this might be interesting for you
    This is the link: %s
    Have a great day!
    Stefaan
    ";
  //No need to amend the code below  
    printf( 
            '<a class="simple-mail-link" href="mailto:?subject=%s&body=%s">
            <div class="label">
            <div class="dashicons dashicons-admin-plugins"></div>
            Forward this to a friend</div></a>',the_title_attribute( 'echo=0' ),
            rawurlencode(sprintf( $content,get_the_permalink()))
            );
?>

Format 2

<?php
  //Start new line by adding \r\n
  //IMPORTANT NOTE: do not remove the %s 
    $content="Hi there, this might be interesting for you\r\nThis is the link: %s\r\nHave a great day!\r\nStefaan";
 //No need to amend the code below          
    printf( 
            '<a class="simple-mail-link" href="mailto:?subject=%s&body=%s">
            <div class="label">
            <div class="dashicons dashicons-admin-plugins"></div>
            Forward this to a friend</div></a>',the_title_attribute( 'echo=0' ),
            rawurlencode(sprintf( $content,get_the_permalink()))
            );              
?>

Demo

<a class="simple-mail-link" href="mailto:?subject=Page%20Title&amp;body=Hi%20there%2C%20this%20might%20be%20interesting%20for%20you%0D%0AThis%20is%20the%20link%3A%20http%3A%2F%2Fblahblahblah.com%0D%0AHave%20a%20great%20day%21%0D%0AStefaan"><div class="label"> <div class="dashicons dashicons-admin-plugins"></div>Forward this to a friend</div></a></body>
Clari answered 14/6, 2016 at 20:13 Comment(2)
@Clari Thank you so much, your solution worked! As you were the first to post it, I'll award you the bounty.Leisure
@Leisure glad to be of help. the problem you had wasn't to do with sprintf() as your original question title suggested but rather how print_r() and sprintf () were nested, that's why you couldn't get it to work with so many different solutions proposed by others. I wrote a detailed explanation in the answer if you are interested.Clari
M
2

According to the e-mail specification, every e-mail line needs to end in the old <CR><LF> pair - so you need to use \r\n in the sprintf() string.

"This is the link: %s.\r\n Have a great day!\r\n Stefaan"

And if \r\n doesn't work, you've got a source-language limitation. Given that:

  • \r is ASCII 13 (hex 0D)
  • \n is ASCII 10 (hex 0A)

perhaps you could use "&#13;&#10;"?

Muckraker answered 11/6, 2016 at 14:5 Comment(2)
Sorry, that didn't work... There's still no break in the email. Also, see my screenshot in my question edit.Leisure
@Stefaan, try my latest edit then. Now you're battling your language, not the e-mail!Muckraker
M
1

Use urlencoded string for CR/LF

%0D%0A

where you want a break.

In example

<a 
 class="simple-mail-link" 
 href="mailto:?subject=hello&body=Hello%0D%0A%0D%0AWorld!"
>
Muldrow answered 14/6, 2016 at 15:18 Comment(3)
Also, better encode the ampersand. Otherwise, you are trying to expand an entity called body, but the final semicolon is not found and some error handling takes place. AFAIK, this is allowed in HTML, but certainly wrong in HTML 4. If you use &amp;, you will be safe in both.Coeternity
@Stefaan, the issue might be with your email client unable to get correct contents from the link. I have seen many such bugs. Better edit the question to include which client on which OS you are using and try other clients.Coeternity
@Leisure I check only on my Mac MailMuldrow
L
0

Add another %s argument to your sprintf() call and pass it the URL-encoded version of the line-feed char %0A (twice):

printf( 
        '<a class="simple-mail-link" href="mailto:?subject=%s&body=%s"><div class="label"><div class="dashicons dashicons-admin-plugins"></div>Forward this to a friend</div></a>', 
        'subject',
        sprintf( 'Hi there, this might be interesting for you. This is the link: %s. %sHave a great day! Stefaan', "link-here", "%0A%0A" )
    );

Edit: Additionally, you could also just add the %0A to the string itself, but you have to remember to escape the % char by adding an extra one before it:

printf( 
        '<a class="simple-mail-link" href="mailto:?subject=%s&body=%s"><div class="label"><div class="dashicons dashicons-admin-plugins"></div>Forward this to a friend</div></a>', 
        'subject',
        sprintf( 'Hi there, this might be interesting for you. This is the link: %s. %%0A%%0AHave a great day! Stefaan', "link-here" )
    );
Lenard answered 14/6, 2016 at 21:33 Comment(0)
C
0

I decided to go through the issue thoroughly and address all the attempts that were made here. If you want a quick answer, look at the currently accepted one.

Working solution

To use a text in mailto: URL body parameter, percent-encode it. In PHP, use rawurlencode(). Subject should be encoded, too.

$subj = "Whatever subject";
$body = "Multi-\r\nline\r\nbody";
printf(
    "mailto:?subject=%s&body=%s",
    rawurlencode($subj),
    rawurlencode($body)
);
mailto:?subject=Whatever%2Osubject&body=Multi-%0D%0Aline%0D%0Abody

To use it as a target of a HTML link, replace characters that have special meaning in HTML with entity references – htmlspecialchars() is used for that in PHP, and Wordpress has a fancier (and filtrable) esc_html().

$subj = "Whatever subject";
$body = "Multi-\r\nline\r\nbody";
printf(
    '<a href="%s">mailto: URL with multi-line body</a>',
    htmlspecialchars(sprintf(
        "mailto:?subject=%s&body=%s",
        rawurlencode($subj),
        rawurlencode($body)
    ), ENT_QUOTES)
);

<a href="mailto:?subject=Whatever%2Osubject&amp;Multi-%0D%0Aline%0D%0Abody">mailto: URL with multi-line body</a>

I am sure that by now, you know how to modify your PHP code to produce such a link.

Debugging the issue

You have to deal with several levels of technologies, each having its own escaping scheme:

  • PHP (e.g. "\n" is a string with a newline, not with a backslash and the letter n; you would need to escape the backslash if you wanted that – "\\n")

  • (s)printf (e.g. to print a literal %, you have to write %%)

  • HTML (e.g. & starts an entity reference; to be taken literally, it should be encoded as the entity reference &amp;)

  • URL (e.g. space is not a valid part of a URL and it must be percent-encoded as %20)

This is too much to do manually and be sure it is correct without examining the intermediate steps. If you get any of the intermediate steps wrong, it is broken as a whole.

  • Did you verify that the PHP code is saved exactly as you wrote it?
  • Did you look at the HTML it produces?
  • And did you try to copy the URL by right-clicking the link in the browser and choosing “Copy Email Address”?

The safe approach is to manually construct the product of last step, and only once it works, proceed and try to produce it programmatically. In this case, such a product is the URL that once pasted into the browser’s location bar opens mail composer with multi-line body pre-filled. You can begin with a simple working example and make it more and more complex, till it meets your needs. When manual construction is too tedious, you have probably chosen a product that is too complex – choose the simplest one that still works the way you want, you can add complexity later.

If you get stuck even with manually building the URL, you are out of luck. Either you have to read more on the topic, reach out for help, or give up. If it is not just you, the problem is somewhere between your browser and your email client. At least one of them has a bug. In my experience with mailto: URLs, this is not uncommon. Even if you get it to work for you, the visitors of your blog may not be so lucky with their setup.


Aside: HTML spec on presented attempts

I took the time to look at what HTML spec says about the issues I see in the attempts that were presented in other answers and in the question itself. Specifically:

  • unencoded ampersand in attribute value
  • newline in attribute value
  • unencoded < and > in HTML markup (<br>) in attribute value

Syntactic level

HTML implementations are pretty robust these days and even the HTML spec became very permissive regarding encoding ampersands (&) into entity references (&amp;; called character references in HTML5), therefore you will usually get away with not doing that. (HTML 4 spec required the encoding, though.)

At the level of actual bytes in the HTML file, quoted attribute values in HTML5 are free to contain almost* any characters, except the quote that is used to quote them (which must be replaced by a character reference).

* For details, see Preprocessing the input stream and ambiguous ampersand in HTML5 spec.

This is why even newline and unencoded <br> are OK inside quoted attribute values. But actually, they are not OK in href (unlike in e.g. title), because…

Semantic level

At the semantic level, when everything is parsed, any string (including empty string) is allowed as attribute value, but specific attributes add further constraints.

This is where HTML bites you – href is specified to contain a valid URL potentially surrounded by spaces, which cannot contain

  • newlines and other space characters in the middle and
  • <, >, and many other characters at all.

These characters have to be percent-encoded. For the actual definition of URL and its syntax, HTML spec defers to other specifications.

Handling invalid URLs is implementation-defined, these machanisms may not be consistent across browsers. Just respect the specifications. My Firefox ignores newlines and preserves spaces – spaces are not allowed in URLs either, but Firefox encodes them before it does anything else with the URL.

Coeternity answered 15/6, 2016 at 18:10 Comment(0)
M
-1

You could add <br> tag in your sprintf (assuming you want to display break line in for HTML):

sprintf( 'Hi there, this might be interesting for you. This is the link: %s.<br> Have a great day!<br> Stefaan',get_the_permalink() )

EDIT:

If you want plain text mail use \r\n and double quotes:

sprintf("Hi there, this might be interesting for you. This is the link: %s.\r\n Have a great day!\r\n Stefaan",get_the_permalink() )
Mckean answered 30/5, 2016 at 11:40 Comment(5)
Hi there, I already tried that. The problem: it doesn't break in the email, it only displays <br>...Leisure
Hi there, sorry I missed your reply. Unfortunately, it doesn't work yet: it still displays on a single line. This is my actual code: <?php printf( '<a class="simple-mail-link" href="mailto:?subject=%s&body=%s"><div class="label"><div class="dashicons dashicons-admin-plugins"></div>Forward this to a friend</div></a>', the_title_attribute( 'echo=0' ), sprintf("Hi there, this might be interesting for you. This is the link: %s.\n Have a great day!\n Stefaan",get_the_permalink() ) ); ?>Leisure
Side note to this: IF your email client sees it as HTML content, the 'normal' line breaks do not work; you need to force them through <br />. Line breaks only work in plain text emails. Also, if you're using a Windows client, you may need to add both linebreaks \r\n...Whicker
@Leisure Did you tried with \r\n? (look at my "EDIT" part)Mckean
Hi there, no It didn't work: not with \r\n, not with <br />Leisure
T
-1

You could probably chuck a PHP_EOL in there

<?php
     printf( 
        '<a class="simple-mail-link" href="mailto:?subject=%s&body=%s"><div class="label"><div class="dashicons dashicons-admin-plugins"></div>Forward this to a friend</div></a>', 
        the_title_attribute( 'echo=0' ),
        sprintf( 'Hi there, this might be interesting for you. This is the link: %s. %sHave a great day! %sStefaan',get_the_permalink(), PHP_EOL, PHP_EOL )
    );
Triturate answered 14/6, 2016 at 20:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.