Office365 Attachment Missing issue in Code Igniter 3 PHP
Flow: When an email is sent using Office365, a draft is initially created. All the attachments are then added to this draft one by one before it is sent to the recipient.
Issue: We noticed that when attachments are uploaded to an Office365 email, they don’t always have sufficient time to attach properly before the email is sent. This results in some attachments not being included in the sent email.
Solution Implemented: To address this, we have implemented a delay for each attachment based on its size to ensure it attaches properly to the email. However, we observed that this solution may not always work when there are many attachments or when there are multiple users sending emails through that mail.
Please help me in resolving this issue.
Below is my code-
function office365_send_old($to, $from, $fromname, $msg, $subject, $cc, $bcc, $attachment, $from_type="", $staffid="")
{
$graph = new Graph();
$graph->setAuthConfig(FCPATH . '/application/third_party/msgraph_sdk/credentials.json');
if($from_type == "system") {
$token_details = get_system_email_access_token('office365');
$token = json_decode($token_details);
if (!empty($token) && $token->access_token != '')
{
$access_token = $token->access_token;
$refresh_token = $token->refresh_token;
$userdetaisl = get_option('office365_user_details');
if(!empty($userdetaisl)){
$userdetails = json_decode($userdetaisl);
$actual_fromname = $userdetails->displayName;
}else{
$actual_fromname = '';
}
$actual_fromemail = get_option('office365_email');
$graph->setAccessToken($access_token);
$graph->setAccessTokenParams((array)$token);
if ($graph->isAccessTokenExpired())
{
$creds = $graph->fetchAccessTokenWithRefreshToken($refresh_token);
//Now update the latest token
update_system_email_access_token('office365', $creds);
}
else
{
$graph->setAccessToken($access_token);
}
}
}else{
$access_token = get_email_access_token($staffid, 'office365');
if (!empty($access_token) && $access_token->access_token != '')
{
$access = json_decode($access_token->access_token);
if(!empty($access_token->user_details)){
$userdetails = json_decode($access_token->user_details);
$actual_fromname = $userdetails->displayName;
}else{
$actual_fromname = '';
}
$actual_fromemail = $access_token->email;
$graph->setAccessToken($access->access_token);
$graph->setAccessTokenParams((array)$access);
if ($graph->isAccessTokenExpired())
{
$creds = $graph->fetchAccessTokenWithRefreshToken($access->refresh_token);
//Now update the latest token
update_email_access_token($staffid, 'office365', json_encode($creds));
}
else
{
$graph->setAccessToken($access->access_token);
$graph->setAccessTokenParams((array)$access);
}
}
}
//We have token so send message
$graph->setBaseUrl("https://graph.microsoft.com/")
->setApiVersion("beta")
->setAccessToken($graph->getAccessToken());
$strMailContent = $msg;
$attachments = [];
if (count($attachment) > 0) {
foreach ($attachment as $attached) {
$fileName = $attached['filename'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (strlen($attached['attachment']) < 150) {
if (file_exists($attached['attachment'])) {
$fileData = chunk_split(base64_encode(file_get_contents($attached['attachment'])), 76, "n") . "rn";
$sizeInBytes = filesize($attached['attachment']);
$mimeTypeOriginal = finfo_file($finfo, $attached['attachment'], FILEINFO_MIME_TYPE);
}
}else{
//PDFs
$mimeTypeOriginal = 'text/plain';
$fileData = base64_encode($attached['attachment']);
$sizeInBytes = strlen(base64_decode($fileData));
}
$mimeType = finfo_buffer($finfo, $fileData, FILEINFO_MIME_TYPE);
$size = @getimagesizefromstring($fileData);
$attachments[] = [
"@odata.type" => "#microsoft.graph.fileAttachment",
"name" => $fileName,
"contentType" => $mimeType,
"contentBytes" => $fileData,
"size" => $sizeInBytes,
"contents" => $attached['attachment'],
"originalMime" => $mimeTypeOriginal
];
}
}
if(!empty($bcc)) {
if (str_contains($bcc, ',') || !filter_var($bcc, FILTER_VALIDATE_EMAIL)) {
$bccRecipients = array();
$bcc_arr = explode(',', $bcc);
foreach ($bcc_arr as $bccvalue) {
$bccRecipients[] = array(
"emailAddress" => array(
"address" => trim($bccvalue)
)
);
}
}else{
$bccRecipients = array(
array(
"emailAddress" => array(
"address" => $bcc
)
)
);
}
}
if(!empty($cc)) {
if (str_contains($cc, ',') || !filter_var($cc, FILTER_VALIDATE_EMAIL)) {
$ccRecipients = array();
$cc_arr = explode(',', $cc);
foreach ($cc_arr as $ccvalue) {
$ccRecipients[] = array(
"emailAddress" => array(
"address" => trim($ccvalue)
)
);
}
}else{
$ccRecipients = array(
array(
"emailAddress" => array(
"address" => $cc
)
)
);
}
}
if(!empty($to)) {
if (is_array($to)) {
$toRecipients = array();
foreach ($to as $tovalue) {
$toRecipients[] = array(
"emailAddress" => array(
"address" => trim($tovalue)
)
);
}
}else{
$toRecipients = array(
array(
"emailAddress" => array(
"address" => $to
)
)
);
}
}
$mailBody = array(
"subject" => $subject,
"body" => array(
"contentType" => "html",
"content" => $strMailContent
),
"sender" => array(
"emailAddress" => array(
"name" => $actual_fromname,
"address" => $actual_fromemail
)
),
"from" => array(
"emailAddress" => array(
"name" => $actual_fromname,
"address" => $actual_fromemail
)
)
);
if(!empty($to)) {
$mailBody['toRecipients'] = $toRecipients;
}
if(!empty($bcc)) {
$mailBody['bccRecipients'] = $bccRecipients;
}
if(!empty($cc)) {
$mailBody['ccRecipients'] = $ccRecipients;
}
//Byte streaming process
//Creating Draft Message
$graph->setApiVersion('v1.0');
$response = $graph->createRequest("POST", "/me/messages")
->attachBody($mailBody)
->execute();
$responseBody = $response->getBody();
$messageId = $responseBody['id'];
//Session Creation
if(!empty($messageId)){
//Create upload session
if(!empty($attachments)) {
foreach ($attachments as $attachmentskey => $attachmentsvalue) {
$mailBodySession =
array(
"AttachmentItem" => array(
"attachmentType" => "file",
"name" => $attachmentsvalue['name'],
"size" => $attachmentsvalue['size']
)
);
$responseSession = $graph->createRequest("POST", "/me/messages/".$messageId."/attachments/createUploadSession")
->attachBody($mailBodySession)
->execute();
$responseSessionBody = $responseSession->getBody();
$messageSessionUrl = $responseSessionBody['uploadUrl'];
//Add Attachments now
//Size of original file
$totalSizeInBytes = $attachmentsvalue['size'];
$limit = 2800000;
$totalSizeInBytesNew = $totalSizeInBytes;
if($attachmentsvalue['originalMime'] == "text/plain"){
$file_contents = $attachmentsvalue['contents'];
}else{
$file_contents = file_get_contents($attachmentsvalue['contents']);
}
$a = $totalSizeInBytes;
$b = $limit;
$exploded_chunks = array();
$sum = 0;
for($n = $b; $n <= $a; $n += $b) {
$sum = $sum + $b;
array_push($exploded_chunks,$b);
}
if($n > $a) {array_push($exploded_chunks, $a-$sum);}
$lastbyteSent = 0;
$arraycheck = [];
if(!empty($exploded_chunks)){
foreach ($exploded_chunks as $key => $value) {
if($key == 0){
$length = $value;
$start = 0;
$end = $length-1;
//Send
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $messageSessionUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => substr($file_contents, $start, $end + 1),
CURLOPT_HTTPHEADER => array(
'Content-Type: application/octet-stream',
'Content-Length: '. $length,
'Content-Range: bytes '.$start.'-'.$end.'/'.$totalSizeInBytesNew
),
));
if($attachmentsvalue['originalMime'] != "text/plain"){
$arraycheck[] = $length;
}
$response = curl_exec($curl);
curl_close($curl);
$lastbyteSent = $end + 1;
}else{
$length = $value;
$start = $lastbyteSent;
$end = ($lastbyteSent + $length) - 1;
//Send
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $messageSessionUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => substr($file_contents, $start, $end + 1),
CURLOPT_HTTPHEADER => array(
'Content-Type: application/octet-stream',
'Content-Length: '. $length,
'Content-Range: bytes '.$start.'-'.$end.'/'.$totalSizeInBytesNew
),
));
if($attachmentsvalue['originalMime'] != "text/plain"){
$arraycheck[] = $length;
}
$response = curl_exec($curl);
curl_close($curl);
$lastbyteSent = $end + 1;
}
}
}
}
}
}
try
{
$response = $graph->createRequest("POST", "/me/messages/".$messageId."/send")
->execute();
add_activity_log(json_encode($response));
return true;
}
catch(Exception $e)
{
add_activity_log($e->getMessage());
return false;
}
}