skip to Main Content

I know this has been covered a lot on stackoverflow but I can’t seem to find a solution to my particular issue.

We have a WP based site hosted in Azure so have needed to write our own plugin to handle email from the site using Azure Communication Services via cURL to post to the REST API.

The original script for this was written by a colleague but i’m now trying to get this to allow users to upload file attachments.

I’ve got so far but now i’m stuck. The emails are sending but nothing is attached.

Can anyone help?

This is our code

<?php
class ACSMailer{

    public static function SendMail($atts){

        $to = $atts['to'];
        $subject = $atts['subject'];
        $message = $atts['message'];
        $headers = $atts['headers'];

        $attachments = [];

        $atch = $atts['attachments'];

        foreach($atch as $atchkey => $atchval) {

            $attachments[] = [
                'name' => basename($atchval),
                'contentType' => mime_content_type($atchval),
                'contentInBase64' => base64_encode(file_get_contents($atchval)),
            ];
        }

        //error_log('HEADERS: '. print_r($atts, true));
        // TODO: Check for HTML and send as plain text

        $settings = get_option('acs_settings_option_name');
        $endpoint = $settings["endpoint"];
        $key = base64_decode($settings["key"]);

        $bodyArray = array(
            'sender' => '[email protected]',
            'content' => array('subject' => $subject, 'html' => $message),
            'importance' => 'normal',
            'recipients' => array('to' => array(array('email' => $to))),
            'attachment' => $attachments,
            'disableUserEngagementTracking' => true
            );
        $bodyStr = json_encode($bodyArray);
        $hashedBodyStr = base64_encode(hash('sha256', $bodyStr, true));

        $dateStr = gmdate('D, d M Y H:i:s T');

        $fullEndpoint = $endpoint . '/emails:send?api-version=2021-10-01-preview';
        $hostStr = str_replace('https://', '', $endpoint);
        $url = str_replace($endpoint, '', $fullEndpoint);
        
        $stringToSign = 'POST' . "n" . $url . "n" . $dateStr . ';' . $hostStr . ';' . $hashedBodyStr;
        $signature = base64_encode(hash_hmac('sha256', $stringToSign, $key, true));
        $uuid = vsprintf( '%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(random_bytes(16)), 4) );


        $curl = curl_init();

        curl_setopt_array($curl, array(
            CURLOPT_URL => $fullEndpoint,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => $bodyStr,
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/json',
                'Date: ' . $dateStr,
                'Authorization: HMAC-SHA256 SignedHeaders=date;host;x-ms-content-sha256&Signature=' . $signature,
                'x-ms-content-sha256: ' . $hashedBodyStr,
                'repeatability-request-id: ' . $uuid,
                'repeatability-first-sent: ' . $dateStr
            ),
        ));

        $response = curl_exec($curl);

        curl_close($curl);

        
        error_log('DATE: '. $dateStr);
        error_log('$endpoint: ' . $endpoint);
        error_log('$fullEndpoint: ' . $fullEndpoint);
        error_log('$key: ' . $key);
        error_log('$bodyStr: ' . $bodyStr);
        error_log('$dateStr: ' . $dateStr);
        error_log('$url: ' . $url);
        error_log('$stringToSign : ' . $stringToSign );
        error_log('$signature: ' . $signature);
        error_log('$uuid: ' . $uuid);
        error_log('$hashedBodyStr: ' . $hashedBodyStr);
        error_log('$bodyArray: ' . print_r($bodyArray, true));
        error_log('API RESPONSE: ' . $response);
        
    }
}

2

Answers


  1. Chosen as BEST ANSWER

    So i managed to get it working with the following code. Basically i played around with the loop that creates the array of attached files. Plus turned out the endpoint was wrong.

    public static function SendMail($atts){
    
        $to = $atts['to'];
        $subject = $atts['subject'];
        $message = $atts['message'];
        $headers = $atts['headers'];
    
        $atch = $atts['attachments'];
        //error_log('$atch: '. print_r($atch, true));
    
        foreach($atch as $atchkey => $atchval) {
    
            $attachments[] = array(
                'name' => basename($atchval),
                'contentType' => mime_content_type($atchval),
                'contentInBase64' => base64_encode(file_get_contents($atchval)),
            );
        }
    
        //error_log('HEADERS: '. print_r($atts, true));
        // TODO: Check for HTML and send as plain text
    
        $settings = get_option('acs_settings_option_name');
        $endpoint = $settings["endpoint"];
        $key = base64_decode($settings["key"]);
    
        $bodyArray = array(
            'senderAddress' => '[email protected]',
            'content' => array('subject' => $subject, 'html' => $message),
            'importance' => 'normal',
            'recipients' => array('to' => array(array('address' => $to))),
            'attachments' => $attachments,
            'disableUserEngagementTracking' => true
            );
        $bodyStr = json_encode($bodyArray);
        $hashedBodyStr = base64_encode(hash('sha256', $bodyStr, true));
    
        $dateStr = gmdate('D, d M Y H:i:s T');
    
        $fullEndpoint = $endpoint . '/emails:send?api-version=2023-03-31';
        $hostStr = str_replace('https://', '', $endpoint);
        $url = str_replace($endpoint, '', $fullEndpoint);
        
        $stringToSign = 'POST' . "n" . $url . "n" . $dateStr . ';' . $hostStr . ';' . $hashedBodyStr;
        $signature = base64_encode(hash_hmac('sha256', $stringToSign, $key, true));
        $uuid = vsprintf( '%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(random_bytes(16)), 4) );
    
    
        $curl = curl_init();
    
        curl_setopt_array($curl, array(
            CURLOPT_URL => $fullEndpoint,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => $bodyStr,
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/json',
                'Date: ' . $dateStr,
                'Authorization: HMAC-SHA256 SignedHeaders=date;host;x-ms-content-sha256&Signature=' . $signature,
                'x-ms-content-sha256: ' . $hashedBodyStr,
                'repeatability-request-id: ' . $uuid,
                'repeatability-first-sent: ' . $dateStr
            ),
        ));
    
        $response = curl_exec($curl);
    
        curl_close($curl);
        
    }
    

    But it's only sending image files. docs, pdf's or zip files aren't being sent.


  2. I have exactly the same behaviour while I attempted to send with curl a pdf to a REST API.

    I tried at home with a my network, everything is fine.

    I tried on azure from VM and AKS, timeout again and again. I tried to move from Load Balancer to NAT gateway as an egress, and it’s still the same thing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search