I don't completely understand and some documentation or help would be appreciated greatly :)
Using PHP I create a MIME by using ezcomponents Mail object. But what I do not understand is:
Do you create an S/MIME message from a original MIME by signing it with openssl_pkcs7_sign ? or do you create an S/MIME from scratch and sign it when its done?
Please bear with me as I try to understand the correct way of doing things.
EDIT: Found this piece of code to illustrate my question better
<?
// Setup mail headers.
$headers = array("To" => "someone#nowhere.net",
"From" => "noone#somewhere.net",
"Subject" => "A signed and encrypted message.");
// Sign the message first
openssl_pkcs7_sign("msg.txt","signed.txt",
"signing_cert.pem",array("private_key.pem",
"password"),array());
// Get the public key certificate.
$pubkey = file_get_contents("cert.pem");
//encrypt the message, now put in the headers.
openssl_pkcs7_encrypt("signed.txt", "enc.txt",
$pubkey,$headers,0,1);
$data = file_get_contents("enc.txt");
// separate header and body, to use with mail function
// unfortunate but required, else we have two sets of headers
// and the email client doesn't decode the attachment
$parts = explode("\n\n", $data, 2);
// send mail (headers in the Headers parameter will override those
// generated for the To & Subject parameters)
mail($mail, $subject, $parts[1], $parts[0]);
?>
Save yourself a lot of pain and route the messages you need signed through a MTA filter that is designed for the job, e.g. Gnu Anubis (SMTP proxy) or implement a milter
Related
I am sending an e-mail from my php code when certain events occur (i.e., someone posts a reply to a message on my message board). I used this simple code:
mail (me#aol.com, 'Someone Just Posted a Reply.', 'Check the message board, because someone just posted a reply.');
The code executes and I do receive an e-mail. The problem is that when I get the e-mail, the "from" line in the e-mail gives away my cpanel login for my GoDaddy hosting account. I cannot seem to find anything on GoDaddy's site that explains how to disguise this or change this to just reflect the name of my website rather than give away my login to all users every time I send a push notification.
You have to use the headers in the PHP's mail() function's additional_headers parameters to add more stuff, but this may possibly cause deliverability issues.
This is typically used to add extra headers (From, Cc, and Bcc). Multiple extra headers should be separated with a CRLF (\r\n). If outside data are used to compose this header, the data should be sanitized so that no unwanted headers could be injected.
With above being said, your updated code should look something like:
<?php
$headers = array(
'From' => 'webmaster#example.com', // Add your from address.
'Reply-To' => 'webmaster#example.com', // Add your reply to address.
'X-Mailer' => 'PHP/' . phpversion() // Optional stuff.
);
mail(
"me#aol.com",
"Someone Just Posted a Reply.",
"Check the message board, because someone just posted a reply.",
$headers // This way
);
Note: Make sure the above code is written in a single line. 😇
I am using a simple php code similar to the standard openssl_pkcs7_sign() example to sign many mails in a loop
http://php.net/manual/en/function.openssl-pkcs7-sign.php
The problem is this code is too I/O intensive. This reads the same certificates and calls the openssl functions in a loop.
Can I just read the certificate in memory and use for signing everytime
This is the relevant part of the script
<?php
$headers = array( "From: Ram <ram#netcore.co.in>", "Subject" => "Signed mail");
/* All the recipients who will get the mail */
$users = array ( 'ram#netcore.co.in' , 'aa#netcore.co.in','bb#netcore.co.in');
foreach ($users as $rcpt){
$headers['To'] = $rcpt;
openssl_pkcs7_sign($rcpt."infile.txt",
"outfile.txt","file://noPassPrivatePublicKey.pem",
array("file://noPassPrivatePublicKey.pem", ""),
$headers);
/* Now make an smtp connection and send the mail */
send_mail_to_smtp($from,$rcpt,"outfile.txt");
}
?>
Sign the mail once and send it to all recipients. S/MIME signs the mail body, only. So setting the To: header afterwards won't invalid the signature.
Could you advise me how do I go about preventing email injection in PHP mail() without losing original message data? E.g. if I need to allow user to use \r\n, To, CC etc, so I do not want to completely strip them away from the message - I still want them delivered, but without adding any additional headers or somehow allowing mail injection to happen.
Most of the advices on internet suggest stripping that data away completely - but I do not want to do that.
I am sending plain text (non HTML) messages through PHP mail() function.
What would you advise?
To filter valid emails for use in the recipient email field, take a look at filter_var():
$email = filter_var($_POST['recipient_email'], FILTER_VALIDATE_EMAIL);
if ($email === FALSE) {
echo 'Invalid email';
exit(1);
}
This will make sure your users only supply singular, valid emails, which you can then pass to the mail() function. As far as I know, there's no way to inject headers through the message body using the PHP mail() function, so that data shouldn't need any special processing.
Update:
According to the documentation for mail(), when it's talking directly to an SMTP server, you will need to prevent full stops in the message body:
$body = str_replace("\n.", "\n..", $body);
Update #2:
Apparently, it's also possible to inject via the subject, as well, but since there is no FILTER_VALIDATE_EMAIL_SUBJECT, you'll need to do the filtering yourself:
$subject = str_ireplace(array("\r", "\n", '%0A', '%0D'), '', $_POST['subject']);
Suppose you you want to put the email address of the visitor in the optional header field like so:
$headers = "From: $visitorEmailAddress";
However, if
$visitorEmailAddress
contains
"address#email.com\n\nBCC:spam#v1agra.com"
you've made yourself a spam host, opening the door for mail injection.
This is a very simple example, but creative spammers and malicious hackers can sneak potentially damaging scripts in your email, since email is sent as a plaintext file. Even attachments are converted plaintext, and they can easily send attachements by adding a mimetype content line.
If your form validation for the FROM and/or TO fields is OK, you have to look at the form validation for the body of the email. I'd strip out the '-=' and '=-' characters, and prevent users from typing plain HTML by using strip_tags().
Try this for a review of various options:
http://www.codeproject.com/Articles/428076/PHP-Mail-Injection-Protection-and-E-Mail-Validatio
It covers several options and tries to explain the benefits and risks of each.
Use a designated mime email library, like Mail_Mime:
<?php
include 'Mail.php';
include 'Mail/mime.php' ;
$mime = new Mail_mime();
$mime->setTXTBody("Message goes here");
$hdrs = $mime->headers(array(
'From' => 'you#yourdomain.com',
'Subject' => 'Test mime message'
));
$body = $mime->get();
$mail = &Mail::factory('mail');
$mail->send('postmaster#localhost', $hdrs, $body);
?>
I'm sending an email with some xheader.
When the recipient of the email replays to that email, i want to parse it, and get the content of that xheader from the mail i get by replay.
unfortunately, when i'm parsing the email i get back, i don't see my xheader.
(I printed the whole email, and the xheader is not there)
How can i do that in PHP with Zend Framework (i'm using Zend_Mail_Storage_Imap)?
Code:
$mail = new Zend_Mail_Storage_Imap(array(
'host' => 'pop.gmail.com',
'user' => 'a#gmail.com',
'password' => 'a',
'ssl' => 'SSL'
));
$count = $mail->countMessages();
$message = $mail->getMessage($count);
print_r($message);
//go through the message
foreach(new RecursiveIteratorIterator($message) as $part){
echo '*****************<br/>';
print_r($part);
echo '<br/>*****************<br/>';
//match parts content type to text/html - the one that maches is the message HTML body
if (preg_match('/.*text\/html.*/', $part->contentType)){
$body = $part->getContent();
}
$headers = $part->getHeaders();
if (isset($headers['X-aHeader'])){
echo $headers['X-aHeader'];
}
Thanks,
Boris.
Pekka gets points for the correct response here - X-headers in an original message will not necessarily be retained for any replies to that message. But, you're using Gmail, so you have another potential option.
Gmail allows plus addressing, so username#gmail.com will also receive mail for username+extra#gmail.com. If your X-aHeader content is alphanumeric, you can append it to your email address (e.g. a+headerdata#gmail.com). If your header content isn't alphanumeric, I'd recommend caching what you would put in the header locally on your system, and provide a uniqid as the email plus-address. When you receive a reply, you can use that uniqid to look up the data you cached locally.
This is a common technique for uniquely identifying recipients who reply to emails, or who perhaps bounce messages.
Is there a way to attach an image to an html formatted email message created in PHP?
We need to ensure that a corporate logo is on emails sent to clients who may not have access to the internet whilst reading their email (They will obviously have it to download the files).
Try the PEAR Mail_Mime package, which can embed images for you.
You need to use the addHTMLImage() method and pass a content id (cid), which is a unique string of text you will also use in your img's src attribute as a cid: URL. For example:
include('Mail.php');
include "Mail/mime.php";
$crlf = "\r\n";
$hdrs = array(
'From' => 'foo#bar.org',
'Subject' => 'Mail_mime test message'
);
$mime = new Mail_mime($crlf);
//attach our image with a unique content id
$cid="mycidstring";
$mime->addHTMLImage("/path/to/myimage.gif", "image/gif", "", true, $cid);
//now we can use the content id in our message
$html = '<html><body><img src="cid:'.$cid.'"></body></html>';
$text = 'Plain text version of email';
$mime->setTXTBody($text);
$mime->setHTMLBody($html);
$body = $mime->get();
$hdrs = $mime->headers($hdrs);
$mail =& Mail::factory('mail');
$mail->send('person#somewhere.org', $hdrs, $body);
It's probably easiest to use some library that can deal with email attachments. For example, PEAR's Mail_Mime.
PEAR's Mail_Mime package is what you're after here.
Once you've set your message up, adding an attachment is as simple as:
$mime = new Mail_mime("\n");
$mime->setTXTBody($msg_text);
$mime->setHTMLbody($msg_html);
// Add gif as attachment to mail
$mime->addAttachment("/path/to/image/smile.gif", "image/gif");
$body = $mime->get();
$headers = $mime->headers($headers);
$mail->send("joe#bloggs.com", $headers, $body);
If you're looking for your logo to display in a particular place in the email - rather than solely as an attachment - you can do the following:
// In your message html:
<img src='logo.gif' alt='Our logo' />
// PHP:
$mime->addHTMLImage('/path/to/image/logo.gif');
This approach can have mixed results depending on your user's mail client, so before sending it out try testing your format on dummy gmail, yahoo and hotmail accounts.
Are you rolling your own, or using a
prefab class? I recommend PHP
Mailer[0] myself, and there's also
PEAR::Mail_Mime[1] among others that
Google would be happy to help you
find. I've been using PHP Mailer to
send messages with embedded images[2]
for years without a hitch, though bear
in mind that each image increases the
email's bandwidth weight hugely, so
generally it should not be used for
anything in bulk. And to echo Bill,
do make use of the text-only alternative too.
[0] http://phpmailer.sourceforge.net/
[1] http://pear.php.net/manual/en/package.mail.mail-mime.php
[2] http://phpmailer.sourceforge.net/docs/PHPMailer/PHPMailer.html#AddEmbeddedImage
taken from http://lists.evolt.org/archive/Week-of-Mon-20060612/183029.html
There are more than enough answers here that should help fix your specific problem, but I just thought it might be worth pointing out that you may well have a larger problem that you hadn't considered.
Specifically - writing emailers to be sent via PHP is filled with potential gotchas and should only be done if you have a really good idea of what can go wrong.
If you're planning on sending emails fairly intensively I would strongly suggest doing it through either a dedicated email marketing client or implementing one of the many email marketing API's out there that will send it for you. (mailchimp is apparently a decent one).
Try out swiftmailer here is a good example how to use embedded image http://swiftmailer.org/wikidocs/v3/embedding_images?s[]=embed