PHPMailer with Outlook365 - imap_append 7KB size limit - php

I have PHPMailer setup to use our Outlook365 server to send emails with attachments. It works great until the script, using imap_append, attempts to add the message to our "sent" folder. What I have discovered is that if the attachment is more than 7KB in size, it fails. Less than 7KB, it works. The recipient receives the attachment either way.
Any idea where this limitation is coming from and how I can increase it?
Here's the code block for saving the messages to the sent folder.
function save_mail($mail) {
global $config;
$MailHost = "{".$config->MailHost."/imap/ssl/novalidate-cert}Sent Items";
$path = $MailHost;
if ($conn = imap_open($path, $config->MailUsername, $config->MailPassword)) {
if (imap_append($conn, $path, $mail->getSentMIMEMessage())) {
$result = true;
} else {
error_log("ERROR: Unable to save mail to 'Sent Items' folder.\n - " . imap_last_error());
$result = false;
}
imap_close($conn);
return $result;
} else {
error_log("ERROR: Unable to connect to IMAP server.");
return false;
}
}

From my testing today, if sending to an Exchange based IMAP server with an attachment or embedded image greater than 7kb, you will need to change the line returns from unix format to windows format. I simply did a string replace on '\n' and replaced with '\r\n' to get this done.
$content = str_replace("\n", "\r\n", $mail->getSentMIMEMessage());

Related

PHPMailer, attachment settings can't access file (csv fiile)

I'm running a PHP script that runs a sequence of SQL queries, writes the results to CSV, and saves it. It also mails the report to a recipient.
The CSV portion of the code works perfectly, and the PHPMailer portion sends the test email with no problem. However, when I un-comment the attachment portion of PHPMailer and run the script it says "File could not be accessed". When I replace the comment, it writes the file and sends the test email again just fine.
The line in question, which I comment/uncomment accordingly, is: $mail->addAttachment($fp);
So, the two pieces are working, but this being my first time using PHPMailer, I'm not sure the best way to go about fixing this. As far as I can tell, I'm using the addAttachment code properly and I'm closing the CSV at the very end.
Any help is much appreciated.
The script:
if (!$result) die('Couldn\'t fetch records');
$num_fields = mysqli_num_fields($result);
$headers = array();
while ($fieldinfo = mysqli_fetch_field($result)) {
$headers[] = $fieldinfo->name;
}
$fp = fopen('dailyReportTestPHP.csv', 'w');
if ($fp && $result) {
fputcsv($fp, $headers);
while ($row = $result->fetch_array(MYSQLI_NUM)) {
fputcsv($fp, array_values($row));
}
}
$mail = new PHPMailer(true);
$address = "hnorman#jacksonfurnind.com";
try{
$mail->setFrom("hnorman#jacksonfurnind.com");
$mail->addAddress($address);
$mail->addAttachment($fp);
$mail->isHTML(true);
$mail->Subject = "Test";
$mail->Body = "Test";
$mail->Send();
echo 'message sent';
} catch (Exception $e){
echo 'message failed';
echo 'mail error:' . $mail->ErrorInfo;
}
fclose($fp);
It's because $fp is an open file handle; PHPMailer is expecting a string containing the path to the file to be passed to addAttachment(). So, move the fclose call to before you create the PHPMailer instance, and then do this:
$mail->addAttachment('dailyReportTestPHP.csv');

How to get live streaming data of Server Sent Events using php?

Hi I'm trying server sent events(SSE) using php, I have a https url where I get the live streaming data. Below is my script where I'm trying in infinite loop.
PHP:
<?php
while(1)
{
$get_stream_data = fopen('https://api.xyz.com:8100/update-stream/connect', 'r');
if($get_stream_data)
{
$stream_data = stream_get_contents($get_stream_data);
$save_stream_data = getStreamingData($stream_data);
if($save_stream_data == true)
{
continue;
}
}
else
{
sleep(1);
continue;
}
}
function getStreamingData($stream_data)
{
$to = "accd#xyz.com";
$subject = "Stream Details";
$msg = "Stream Details : ".$stream_data;
$headers = "From:streamdetail#xyz.com";
$mailsent = mail($to,$subject,$msg,$headers);
if($mailsent){
return true;
}else {
return false;
}
}
?>
Error:
Warning: fopen(https://api.xyz.com:8100/update-stream/connect): failed to open stream: Connection timed out in /home/public_html/get_stream_data/index.php on line 4
I couldn't get the data by my end while it is giving an updates by the server in live.
I checked that live streaming in a command prompt using below command.
CURL
curl --get 'https://api.xyz.com:8100/update-stream/connect' --verbose
First, this is best done with PHP's curl functions. See the various answers to PHP file_get_contents() returns "failed to open stream: HTTP request failed!"
If you stick with fopen() you probably need to set up the context for SSL, and it may involve installing some certificates. See file_get_contents(): SSL operation failed with code 1. And more (and note the security warning about the accepted answer)
Finally, your while(1) loop is around the fopen() (which is okay for re-starts after relatively rare failures), but you actually want it inside. Here is your code with just the minimal changes to show that:
<?php
while(1)
{
$get_stream_data = fopen('https://api.xyz.com:8100/update-stream/connect', 'r');
if($get_stream_data)while(1)
{
$stream_data = stream_get_contents($get_stream_data);
$save_stream_data = getStreamingData($stream_data);
if($save_stream_data == true)
{
continue;
}
sleep(1);
}
else
{
sleep(1);
continue;
}
}
UPDATE: The above code still nags at me: I think you want me to using fread() instead of stream_get_contents(), and use blocking instead of the sleep(1) (in the inner loop).
BTW, I'd suggest changing the outer-loop sleep(1) to be sleep(3) or sleep(5) which are typical defaults in Chrome/Firefox/etc. (Really, you should be looking for the SSE server sending a "retry" header, and using that number as the sleep.)

Php email attachment extraction

I'm trying to create a piece of code that will go into the mailbox and take out the attachments of a specific file. So far I am only able to view if there is an attachment or if there is not an attachment on the e-mail.
But I want it to be able to take the attachments out of the e-mail and then save them to a specified directory. The type of attachment I'm trying to take out is a .jpg
I've tried a bunch of different pieces of code that I've found on google and I've been trying to tailor it to fit into my code, but so far I have been unsuccessful in finding anything that works correctly.
I was wondering if anyone would be able to help me create a piece of code that would be able to take the attachments out of the emails and store them in a directory.
Thanks.
<?php
/* connect to email */
$hostname = '{*****.com:110/pop3}INBOX';
$username = '*****';
$password = '*****';
// try to connect
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect to server: ' . imap_last_error());
// grab emails
$emails = imap_search($inbox,'ALL');
// Search for the 39th email, which has an attachment
$count = 39;
// Fetch all the information about an email
$attachment = imap_fetchstructure($inbox, $count);
// find out how may parts the object has
$numparts = count($attachment->parts);
// find if if multipart message
if ($numparts >= 2) {
foreach ($attachment->parts as $part) {
if ($part->disposition == "INLINE") {
// inline message. Show number of lines
printf("Inline message has %s lines<BR>", $part->lines);
} elseif ($part->disposition == "ATTACHMENT") {
// an attachment
echo "Attachment found!";
// print out the file name
echo "Filename: ", $part->dparameters[0]->value;
}
}
}
//}
else {
// only one part so get some useful info
echo "No attachment";
}
imap_close($imap);
?>
Instead of imap_search I used imap_check to retrieve messages overview, and the following worked.
Go over messages found with imap_check, and this is how you extract the binary data of attachment:
$mbox = imap_open( . . . . );
$IMAPobj = imap_check($inbox);
$start = $IMAPobj->Nmsgs-30;
$end = $IMAPobj->Nmsgs;
$result = imap_fetch_overview($inbox,"$start:$end",0);
$count = $end;
foreach ($result as $overview) {
$parts = mail_mime_to_array($inbox, $count);
foreach($parts as $part) {
if(#$part['filename'] || #$part['name'] ) {
$partName = $part['filename'] ? $part['filename'] : $part['name'];
echo "Attachment name is " . basename($partName);
echo "\n";
if(preg_match( . . . write here a regex to detect ".jpg" in $partName . . .)) {
echo "Found file! Extracting binary data...";
$fileContents = $part['data'];
file_put_contents("attachment.jpg", $fileContents);
}
}
}
}

fgets() halting without error in Swiftmailer

I'm attempting to generate a test email in Laravel 4.2 (Windows 7, IIS 6.1), and I've encountered a silent termination - it just fails, doesn't return my view, and doesn't return an error or Exception. I've managed to brute force my way through the Laravel codebase and located the termination within Swift\Transport\AbstractSmtpTransport::_getFullResponse(), specifically the line $line = $this->_buffer->readLine($seq);:
protected function _getFullResponse($seq)
{
$response = '';
try {
do {
$line = $this->_buffer->readLine($seq);
$response .= $line;
} while (null !== $line && false !== $line && ' ' != $line{3});
} catch (Swift_IoException $e) {
$this->_throwException(
new Swift_TransportException(
$e->getMessage())
);
} catch (Swift_TransportException $e) {
$this->_throwException($e);
}
return $response;
}
That do loop executes twice. The first time $line is assigned the value * OK The Microsoft Exchange IMAP4 service is ready., which is great, as obviously I'm getting to the server. Unfortunately, the second iteration fails in Swift\Transport\StreamBuffer::readLine() at the line $line = fgets($this->_out); :
public function readLine($sequence)
{
if (isset($this->_out) && !feof($this->_out)) {
$line = fgets($this->_out);
if (strlen($line)==0) {
$metas = stream_get_meta_data($this->_out);
if ($metas['timed_out']) {
throw new Swift_IoException(
'Connection to ' .
$this->_getReadConnectionDescription() .
' Timed Out'
);
}
}
return $line;
}
}
I've tried wrapping that line in a try/catch, and nothing happens, the code just halts with no information on the second iteration of the do loop. So, any advice as to a) how to squeeze more information out of the halt or b) what could cause fgets() to halt this way?
Ok, progress: after broadening my search to Swiftmailer in general, I was able to find mention of a timeout occurring at that particular line in Swiftmailer. By extending the max_execution_time in php.ini I was able to get an actual Exception:
Expected response code 220 but got code "", with message "* OK The Microsoft Exchange IMAP4 service is ready. * BYE Connection is closed. 13 "
I think under the circumstances I'll close this question and move onto figuring out why I'm not getting a 220.

Get inline email attachments with PHP in a formatted email send from an IOS device

I'm using PHP-imap to read emails and there attachments from a IMAP Account. The emails are send from an iPhone or iPad. It works fine when they write an email and paste in an image they took.
Here's a snippet how I get the attachments:
require_once("plugins/MailLib/MailLib.php");
$mailbox = new MailLib();
$mailbox->connect($username, $password, $server, $port, $path, false);
$mails = array();
$mailIds = $mailbox->getMails("UNSEEN");
if($mailIds != null && count($mailIds) > 0) {
foreach($mailIds as $mailId) {
$mail = $mailbox->getMail($mailId);
if($mail['attachments']) {
foreach($mail['attachments'] as $attachment) {
$file = $mailbox->getAttachment($attachment, $mailId);
$destFile = "path/to/folder/".time().".jpg";
$fh = fopen($destFile, 'a') or die("can't open file");
fwrite($fh, $file);
fclose($fh);
}
}
}
It all crashes as soon as they start formatting the content with the default options like bold, italic or underline. Because then I get the following email content:
<div>
<em>Test</em> with <strong>formatting</strong>
<br>
<br>
<img id="7CB777EB-3124-4AEA-8894-6F743EA78F79" src="cid:7CB777EB-3124-4AEA-8894-6F743EA78F79" alt="image.jpeg">
<br>
<br>
<div>Send from my iPhone</div>
</div>
Is there any kind of php library out there to get those attachments as well?
I found a solution for the problem. Someone wrote a small class to extract inline attachments.
With this class it is possible to write the attachment content direct to a file, like the following:
foreach($emailMessage->attachments as $attachment) {
file_put_contents(time().".extension", $attachment['data']);
}

Categories