add inline image to a message sent with swiftmailer - php

Please excuse my php but, Im using Swiftmailer to send emails from a clients website. They've requested to add an image or two as a signature etc and so looking at the swiftmailer spec here
http://swiftmailer.org/docs/messages.html
They suggest either adding an inline image like this
$message->embed(Swift_Image::fromPath('http://site.tld/image here'))
or like this(in 2 steps)
$cid = $message->embed(Swift_Image::fromPath('image here'));
then in the emails body section add
<img src="' . $cid . '" alt="Image" />'
Both steps ive tried but to no avail. When i hit the send email button, i get this error which i dont quite know what to make of it.
Call to a member function embed() on a non-object in /home/content/78/5152878/html/4testing/erase/ask-doc-proc2.php on line 89
The only thing i added to my already working code and email was the image code directly from the example in the docs pages. This error obviously prevents the email from being sent. if i remove it then it sends emails fine. Since i need to add an image to this,
Any help is greatly appreciated. Thank you
edit: this is the portion where the email is built and sent
$cid= $message->embed(Swift_EmbeddedFile::fromPath('http://myforecyte.com/dev/pic.jpg'));
->setTo( $docEmail)
->setBody("Hello" . "\r\n\r\n" .
$fullName . " has visited MyForeCYTE.com. Upon their visit they have requested to learn more about the test. \r\n\r\n" .
"Please visit www.ClarityWomensHealth.com to find out more about The ForeCYTE Breast Health Test, or call our customer support line at 1 (877) 722-6339. \r\n\r\n" .
"We look forward to hearing from you. \r\n\r\n" .
"Thank You," , 'text/plain')
->addPart("Hello" . ",</b><br/><br/>" .
"<b>" . $fullName . "</b> has visited www.MyForeCYTE.com. Upon their visit they have requested to learn more about the test. <br/>" .
"Please visit www.ClarityWomensHealth.com to find out more about The ForeCYTE Breast Health Test, or call our customer support line at 1 (877) 722-6339.<br/> " .
"We look forward to hearing from you. <br/><br/><br/>" . "<img src='" . $cid. "' alt='pic'/>" .
"Thank you " , 'text/html')
;

After all the running around i found an alternate solution. Swiftmailer allows 2 methods in which to perform the same thing.
one is the embed() function
and the other one is the attach() function
so to the code above, i removed the "embed()" since it wasn't working for me and added these 2 lines below and it works
->attach(Swift_Attachment::fromPath('path to image here.jpg')
->setDisposition('inline'));
and it worked 100%

None of the answers really worked for me. I had to include inline images, using CID. What I had to do, to make it work:
$attachment = Swift_Image::newInstance($data, $filename, $mimeType)
->setDisposition('inline');
$cid = $message->embed($attachment); // Generates "cid:something"
Important part is using Swift_Image class. Then the image in html should be:
<img src="cid:something" ... />
I think this solution works without doing something hacky with swiftmailer (ver. 5.4.2). It is exactly how the documentation says.
Remember to test multiple email clients (gmail, thunderbird, apple mail, web clients...) if the inline images work. For example using Swift_Attachment, inline images showed in gmail, but not in some web clients. Using Swift_Image, it worked everywhere.

The accepted answer doesn't work (version tested: 5.4.2).
(Mine works but could be perfected)
Instead, looking inside the "Original" (Gmail: Show Original) I've found that swiftmailer is omitting adding 2 headers to the attachment, namely:
Content-ID: <ABC123>
X-Attachment-Id: ABC123
ABC123 is the cid we have to put in the body where we want the inline to be showed:
So thanks to this question: I found the way to fix it for swiftmailer (that is even against swiftmailer documentation, but it works while theirs do not)
this is the final (ugly) code:
$attachment = Swift_Attachment::fromPath('image.jpg')->setDisposition('inline');
$attachment->getHeaders()->addTextHeader('Content-ID', '<ABC123>');
$attachment->getHeaders()->addTextHeader('X-Attachment-Id', 'ABC123');
$cid = $message->embed($attachment);
$img = '<img src="cid:ABC123"/>';
$html = "
<html>
<head>
</head>
<body>
$img
</body>
</html>
";
$message->setBody($html, 'text/html');

I know this is an old question (with an accepted answer), but for anyone having the same problem, the Swift_Image::fromPath($image_path) method expects the image path to be local (a filesystem path):
Swift_Image::fromPath("/local/path/to/image.jpg");
// Local path = great success
Thus the below will fail if your image path is external (starting with https://, etc.):
Swift_Image::fromPath("https://external.path/to/image.jpg");
// External path = epic fail
For external images, you should use:
# Load the image file
$data = file_get_contents($image_path);
# Get the filename
$filename = explode("?",basename($image_path))[0];
# Get the mime type
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mime_type = $finfo->buffer($buffer);
# Load the image file
$image_file = new \Swift_Image($data, $filename, $mime_type);
# Set the disposition to inline
$image_file->setDisposition('inline');

If you use laravel, try to add public_path() at the beginning of the path, e.g.:
<img src="<?php echo $message->embed(public_path().'/img/backend/name.jpg); ?>">

Related

How to prevent phpmailer sending embedded image as an attachment on Gmail?

I am sending an email with the logo of a company in it. However, I find it annoying when it shows the .png file on the list of emails on Gmail. Upon clicking the email, the logo is there and there's no attachment (which is good). But I really need to remove the file when viewing on the email list. See the image below.
is there a way where I can remove this "email-logo.png"?
.
.
$mail->AddEmbeddedImage('img/email-logo.png','logo');
.
.
$mail->Body = "<img src='cid:logo'>";
.
.
You can try using
$mail->clearAttachments();
I resolved to putting the src attribute of the image to a remote link e.g src="http://somesite.com/image.png". I resolved to this since I always saw embedded images always coming as attachments as you have mentioned. But some clients block remote content as I have seen with this.

Saving Attachment from Email Part using PHP

I've come across a bit of a problem and was wondering if anyone could point me in the right direction, I'm writing a email parser that parses emails and extracts particular info.
It parses plain text emails(the emails are in a set format) using regex, this works fine.
If an email has an attachment which is of type 3 && encoding = 3 && disposition = attachment then save the attachment to local disk.
My problem is step 2:
I foreach through each email structure if it has more than 2 parts I attempt to decode the attachment and save it to disk, but this is failing.
If I try to simply use file_put_contents I get a 0 KB File, I have given full permissions to the wamp server user, So I do not think it's file permissions and I have verified I can write by using mkdir.
file_put_contents(APPPATH . "attachments/". $partofpart->dparameters[0]->value, $partofpart); //$partofpart is part[2] of the full email structure
So I attempted to decode the part and save the decoded part instead using file_put_contents
$attachment = base64_decode($partofpart);
var_dump($attachment);
//then save the attachment with attachment name
file_put_contents(APPPATH . "attachments/". $partofpart->dparameters[0]->value, $attachment);
but this returns an error saying base64_decode requires an string not an object, how do I then convert my email-part-attachment to a string for use by base64_decode?
Even just writing that out I feel I'm missing something obvious and shouldn't require the extra steps.
Am I right in thinking the part IS the attachment? All the parameters lead me to believe so, Type, Subtype, size etc are all correct for the attachment.
Link to the entire scraper model
Thanks for reading and any help.
Below is a vardump of parts that meet the type/encoding/disposition checks
I have worked out the problem, I was not fetching the actual pdf back just its structure
So I wrote a function to retrieve the body of the particular email then used imap_base64 to encode then finally file_put_contents.
function getAttachment($msg_index, $part)
{
$mailbody = imap_fetchbody($this->conn,$msg_index,$part);
return $mailbody;
}
$attachment = imap_base64($this->email_model->getAttachment($email['index'], "2"));
//mkdir(APPPATH . "attachmentzs/");
//then save the attachment with attachment name
file_put_contents(APPPATH . "attachments/". $partofpart->dparameters[0]->value, $attachment);

Glass Mirror API save attatchment image to server via PHP

I am using the PHP quick start project example to display the timeline's attachment (image):
<?php
if ($timeline_item->getAttachments() != null) {
$attachments = $timeline_item->getAttachments();
foreach ($attachments as $attachment) { ?>
<img src="<?php echo $base_url .
'/attachment-proxy.php?timeline_item_id=' .
$timeline_item->getId() . '&attachment_id=' .
$attachment->getId() ?>" />
<?php
}
}
?>
Now I need to save the image to the server so I can resize it and use it elsewhere.
I have tried a few variations of file_put_contents, fopen, and curl but it seems attachment-proxy.php is not returning the image in a format that any of these expect.
How can save a Timeline Attachment to my server?
SOLUTION: Based on Prisoner's response I took another look at the attachment-proxy.php file. It is returning the image as a string. I had unsuccessfully tried file_put_contents($img, file_get_contents("attachment-proxy.php....")); before.
Turns out I don't need the file_get_contents() part.
I altered the last few lines of attachment-proxy.php to this:
$img = $_GET['timeline_item_id'].'.jpg';
$image = download_attachment($_GET['timeline_item_id'], $attachment);
file_put_contents($img, $image);
It works. It saves the image to my server with the ID as the file name.
Thanks.
Have you checked to see what it is returning? The attachment_proxy.php requires OAuth to have been completed, and will redirect you through the OAuth flow if this hasn't been done. So it may very well be that it is saving the HTML for the OAuth login page, or the information from the redirect page.
However, if you're trying to setup something on your server that calls your own server's attachment_proxy.php page... you're jumping through additional unnecessary hoops.
You can probably take a look directly at attachment_proxy.php to see how it is getting the attachment data from Google's servers, and then use this same method to get them and store them on your server instead of just feeding it out for the img tag. Looking at https://github.com/googleglass/mirror-quickstart-php/blob/master/attachment-proxy.php it seems like most of the work is done in a call to download_attachments() which is located in https://github.com/googleglass/mirror-quickstart-php/blob/master/mirror-client.php. You should be able to either borrow the code from download_attachments() or call it directly yourself.

How to specify an email drop location

I'm using Drupal CMS on top of PHP and IIS. When I send emails containing embed images, the images are not displayed in Outlook.
I'm trying to isolate the problem.
There is nothing in Drupal or Outlook which will allow me to view the complete message body with headers.
Is there a way to configure PHP to write the email to a folder on disk instead of sending the email?
you can write it to a text file instead of sending, just need to find the place where it happens:
$folder=dirname(__FILE__)."/emaildir";
$txtfilename=time().'.txt';
$emailstr=$header . "/n" . $message . "/n";
instead of mailto() or whatever function just write to file
$fh=fopen($txtfilename,"w");
$fwrite($fh,$emailstr);
fclose($fh);
This is written from my head, you might want to check for mistakes but you get the picture

How to extract mail atachment with PHP?

I'm extracting emails from a database where they're stored as strings. I need to parse these emails to extract their attachments. I guess there must already be some library to do this easily but I can't find any.
PHP has a MailParse extension that is a lot faster then using the PEAR alternative which is native PHP.
Here is a library that wraps this extension:
http://code.google.com/p/php-mime-mail-parser/
Example:
// require mime parser library
require_once('MimeMailParser.class.php');
// instantiate the mime parser
$Parser = new MimeMailParser();
// set the email text for parsing
$Parser->setText($text);
// get attachments
$attachments = $Parser->getAttachments();
PEAR::Mail::mimeDecode should do what you're looking for
This could be done using the Zend_Mail component of the Zend Framework
Maybe this example, which can also be found in the documentation helps:
// get the first none multipart part
$part = $message;
while ($part->isMultipart()) {
$part = $message->getPart(1);
}
echo 'Type of this part is ' . strtok($part->contentType, ';') . "\n";
echo "Content:\n";
echo $part->getContent();
I don't know however how you can tell Zend Mail to read from strings, maybe there's some work required to do this, but then you'd have a full-fletched library that does what you want and some more(like reading the subject, etc.).
Edit:
I just had a second look at it and realized that all you have to do is write an own storage implementation(subclass Zend_Mail_Storage_Abstract) which shouldn't be so hard to do.
I think that's the cleanest solution you'll get, albeit a little effort is required to make it work.
If you're looking for a more quick'n'dirty kind of solution someone else might be able to help you.
Hope that helps.
PhpMimeParser - parse multipart mime message(attachments, inline images, base64, quoted-printable) https://github.com/breakermind/PhpMimeParser You can cut mime messages from files, string.
// Load .eml mime message from file
$str = file_get_contents('mime-mixed-related-alternative.eml');
// Format output
echo "<pre>";
// Create object MimeParser
$m = new PhpMimeParser($str);
// Show Emails
print_r($m->mTo);
print_r($m->mFrom);
print_r($m->mBcc);
print_r($m->mCc);
// Show Message
echo $m->mSubject;
echo $m->mHtml;
echo $m->mText;
print_r($m->mInlineList);
// Show Files
print_r($m->mFiles);
E-mail attachments are MIME encoded and added to the message body using headers. The PEAR MIME decode package will do what you need:
http://pear.php.net/package/Mail_mimeDecode
There's a better library out there:
https://github.com/php-mime-mail-parser/php-mime-mail-parser
It is installable via Composer.
Since this has the same name as the one on Google Code that was linked to elsewhere in this SO post, I think it's the successor to it, but I can't tell. The authorship info is harder to find on Google Code, so I cannot confirm it's the same author.
Some sample code (from the project README):
// Include the library first
require_once __DIR__.'/vendor/autoload.php';
$path = 'path/to/mail.txt';
$Parser = new PhpMimeMailParser\Parser();
$Parser->setStream(fopen($path, "r"));
// Loop through all the Attachments
if (count($attachments) > 0) {
foreach ($attachments as $attachment) {
echo 'Filename : '.$attachment->getFilename().'<br />'; // logo.jpg
echo 'Filesize : '.filesize($attach_dir.$attachment->getFilename()).'<br />'; // 1000
echo 'Filetype : '.$attachment->getContentType().'<br />'; // image/jpeg
echo 'MIME part string : '.$attachment->getMimePartStr().'<br />'; // (the whole MIME part of the attachment)
}
}

Categories