I\'m trying to implement a code to send HTML email with embedded image.
I already tried for simple HTML email with image but this image is taken from server.
Here is a way to get a string variable without having to worry about the coding.
If you have Mozilla Thunderbird, you can use it to fetch the html image code for you.
I wrote a little tutorial here, complete with a screenshot (it's for powershell, but that doesn't matter for this):
powershell email with html picture showing red x
And again:
How to embed images in email
PHPMailer has the ability to automatically embed images from your HTML email. You have to give full path in the file system, when writing your HTML:
<img src="/var/www/host/images/photo.png" alt="my photo" />
It will automaticaly convert to:
<img src="cid:photo.png" alt="my photo" />
I would strongly recommend using a library like PHPMailer to send emails.
It's easier and handles most of the issues automatically for you.
Regarding displaying embedded (inline) images, here's what's on their documentation:
Inline Attachments
There is an additional way to add an attachment. If you want to make a HTML e-mail with images incorporated into the desk, it's necessary to attach the image and then link the tag to it. For example, if you add an image as inline attachment with the CID my-photo, you would access it within the HTML e-mail with
<img src="cid:my-photo" alt="my-photo" />
.In detail, here is the function to add an inline attachment:
$mail->AddEmbeddedImage(filename, cid, name);
//By using this function with this example's value above, results in this code:
$mail->AddEmbeddedImage('my-photo.jpg', 'my-photo', 'my-photo.jpg ');
To give you a more complete example of how it would work:
<?php
require_once('../class.phpmailer.php');
$mail = new PHPMailer(true); // the true param means it will throw exceptions on errors, which we need to catch
$mail->IsSMTP(); // telling the class to use SMTP
try {
$mail->Host = "mail.yourdomain.com"; // SMTP server
$mail->Port = 25; // set the SMTP port
$mail->SetFrom('name@yourdomain.com', 'First Last');
$mail->AddAddress('whoto@otherdomain.com', 'John Doe');
$mail->Subject = 'PHPMailer Test';
$mail->AddEmbeddedImage("rocks.png", "my-attach", "rocks.png");
$mail->Body = 'Your <b>HTML</b> with an embedded Image: <img src="cid:my-attach"> Here is an image!';
$mail->AddAttachment('something.zip'); // this is a regular attachment (Not inline)
$mail->Send();
echo "Message Sent OK<p></p>\n";
} catch (phpmailerException $e) {
echo $e->errorMessage(); //Pretty error messages from PHPMailer
} catch (Exception $e) {
echo $e->getMessage(); //Boring error messages from anything else!
}
?>
Regarding your comment, you asked how to send HTML email with embedded images, so I gave you an example of how to do that.
The library I told you about can send emails using a lot of methods other than SMTP.
Take a look at the PHPMailer Example page for other examples.
One way or the other, if you don't want to send the email in the ways supported by the library, you can (should) still use the library to build the message, then you send it the way you want.
For example:
You can replace the line that send the email:
$mail->Send();
With this:
$mime_message = $mail->CreateBody(); //Retrieve the message content
echo $mime_message; // Echo it to the screen or send it using whatever method you want
Hope that helps. Let me know if you run into trouble using it.
Based on Arthur Halma's answer, I did the following that works correctly with Apple's, Android & iOS mail.
define("EMAIL_DOMAIN", "yourdomain.com");
public function send_email_html($to, $from, $subject, $html) {
preg_match_all('~<img.*?src=.([\/.a-z0-9:_-]+).*?>~si',$html,$matches);
$i = 0;
$paths = array();
foreach ($matches[1] as $img) {
$img_old = $img;
if(strpos($img, "http://") == false) {
$uri = parse_url($img);
$paths[$i]['path'] = $_SERVER['DOCUMENT_ROOT'].$uri['path'];
$content_id = md5($img);
$html = str_replace($img_old,'cid:'.$content_id,$html);
$paths[$i++]['cid'] = $content_id;
}
}
$uniqid = md5(uniqid(time()));
$boundary = "--==_mimepart_".$uniqid;
$headers = "From: ".$from."\n".
'Reply-to: '.$from."\n".
'Return-Path: '.$from."\n".
'Message-ID: <'.$uniqid.'@'.EMAIL_DOMAIN.">\n".
'Date: '.gmdate('D, d M Y H:i:s', time())."\n".
'Mime-Version: 1.0'."\n".
'Content-Type: multipart/related;'."\n".
' boundary='.$boundary.";\n".
' charset=UTF-8'."\n".
'X-Mailer: PHP/' . phpversion();
$multipart = '';
$multipart .= "--$boundary\n";
$kod = 'UTF-8';
$multipart .= "Content-Type: text/html; charset=$kod\n";
$multipart .= "Content-Transfer-Encoding: 7-bit\n\n";
$multipart .= "$html\n\n";
foreach ($paths as $path) {
if (file_exists($path['path']))
$fp = fopen($path['path'],"r");
if (!$fp) {
return false;
}
$imagetype = substr(strrchr($path['path'], '.' ),1);
$file = fread($fp, filesize($path['path']));
fclose($fp);
$message_part = "";
switch ($imagetype) {
case 'png':
case 'PNG':
$message_part .= "Content-Type: image/png";
break;
case 'jpg':
case 'jpeg':
case 'JPG':
case 'JPEG':
$message_part .= "Content-Type: image/jpeg";
break;
case 'gif':
case 'GIF':
$message_part .= "Content-Type: image/gif";
break;
}
$message_part .= "; file_name = \"$path\"\n";
$message_part .= 'Content-ID: <'.$path['cid'].">\n";
$message_part .= "Content-Transfer-Encoding: base64\n";
$message_part .= "Content-Disposition: inline; filename = \"".basename($path['path'])."\"\n\n";
$message_part .= chunk_split(base64_encode($file))."\n";
$multipart .= "--$boundary\n".$message_part."\n";
}
$multipart .= "--$boundary--\n";
mail($to, $subject, $multipart, $headers);
}
You have to encode your email as multipart mime and then you can attach emails as attachments basically. You reference them by cid in the email.
Alternatively you could not attach them to the email and use URLs directly but most mail programs will block this as spammers use the trick to detect the liveness of email addresses.
You don't say what language but here is one example.
I'm using this function that find all images in my letter and attaches it to the message.
Parameters: Takes your HTML (which you want to send);
Return: The necessary HTML and headers, which you can use in mail()
;
Example usage:
define("DEFCALLBACKMAIL", "yourmail@yourdomain.com"); // WIll be shown as "from".
$final_msg = preparehtmlmail($html); // give a function your html*
mail('your@mail.com', 'your subject', $final_msg['multipart'], $final_msg['headers']);
// send email with all images from html attached to letter
function preparehtmlmail($html) {
preg_match_all('~<img.*?src=.([\/.a-z0-9:_-]+).*?>~si',$html,$matches);
$i = 0;
$paths = array();
foreach ($matches[1] as $img) {
$img_old = $img;
if(strpos($img, "http://") == false) {
$uri = parse_url($img);
$paths[$i]['path'] = $_SERVER['DOCUMENT_ROOT'].$uri['path'];
$content_id = md5($img);
$html = str_replace($img_old,'cid:'.$content_id,$html);
$paths[$i++]['cid'] = $content_id;
}
}
$boundary = "--".md5(uniqid(time()));
$headers .= "MIME-Version: 1.0\n";
$headers .="Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
$headers .= "From: ".DEFCALLBACKMAIL."\r\n";
$multipart = '';
$multipart .= "--$boundary\n";
$kod = 'utf-8';
$multipart .= "Content-Type: text/html; charset=$kod\n";
$multipart .= "Content-Transfer-Encoding: Quot-Printed\n\n";
$multipart .= "$html\n\n";
foreach ($paths as $path) {
if(file_exists($path['path']))
$fp = fopen($path['path'],"r");
if (!$fp) {
return false;
}
$imagetype = substr(strrchr($path['path'], '.' ),1);
$file = fread($fp, filesize($path['path']));
fclose($fp);
$message_part = "";
switch ($imagetype) {
case 'png':
case 'PNG':
$message_part .= "Content-Type: image/png";
break;
case 'jpg':
case 'jpeg':
case 'JPG':
case 'JPEG':
$message_part .= "Content-Type: image/jpeg";
break;
case 'gif':
case 'GIF':
$message_part .= "Content-Type: image/gif";
break;
}
$message_part .= "; file_name = \"$path\"\n";
$message_part .= 'Content-ID: <'.$path['cid'].">\n";
$message_part .= "Content-Transfer-Encoding: base64\n";
$message_part .= "Content-Disposition: inline; filename = \"".basename($path['path'])."\"\n\n";
$message_part .= chunk_split(base64_encode($file))."\n";
$multipart .= "--$boundary\n".$message_part."\n";
}
$multipart .= "--$boundary--\n";
return array('multipart' => $multipart, 'headers' => $headers);
}