1

I am using gmail API to send an email .In this the sending is successfully done. i want to know how to reply to that person ( who already send ) using php.

Here i attach my code for sending :

$line = "\n";
$strMailContent = $message;
$strMailTextVersion = strip_tags($strMailContent, '');

$strRawMessage = "";
$boundary = uniqid(rand(), true);
$subjectCharset = $charset = 'utf-8';

$strToMail = $to;

$strSubject = $subject;

$strRawMessage .= 'To: ' . ($strToMail)  . "\r\n";

if(!empty($_POST['cc']) || !empty($_POST['bcc'])){
    $cc = $_POST['cc'];
    $bcc = $_POST['bcc'];
    $strRawMessage .= "Cc: $cc". $line;
    $strRawMessage .= "Bcc: $bcc". $line;
}

$strRawMessage .= 'Subject: =?' . $subjectCharset . '?B?' . base64_encode($strSubject) . "?=\r\n";
$strRawMessage .= 'MIME-Version: 1.0' . "\r\n";
$strRawMessage .= 'Content-type: Multipart/Mixed; boundary="' . $boundary . '"' . "\r\n";



$filePath = $file_tmp_name;
$mimeType =  'text/plain; charset="UTF-8" ';
$fileName = $file_name;
$fileData = base64_encode(file_get_contents($filePath));

$strRawMessage .= "\r\n--{$boundary}\r\n";
$strRawMessage .= 'Content-Type: '. $mimeType .'; name="'. $fileName .'";' . "\r\n";            
$strRawMessage .= 'Content-Description: ' . $fileName . ';' . "\r\n";
$strRawMessage .= 'Content-Disposition: attachment; filename="' . $fileName . '"; size=' . filesize($filePath). ';' . "\r\n";
$strRawMessage .= 'Content-Transfer-Encoding: base64' . "\r\n\r\n";
$strRawMessage .= chunk_split(base64_encode(file_get_contents($filePath)), 76, "\n") . "\r\n";
$strRawMessage .= '--' . $boundary . "\r\n";



$strRawMessage .= $strMailContent;

$mime = rtrim(strtr(base64_encode($strRawMessage), '+/', '-_'), '=');

$base64 = base64_encode($mime);
$data = '{ "raw" : "'.$mime.'" }';
$send = Qassim_HTTP(1, $url, $header, $data);

Here i pass the To address as already sended person mail id and the subject is already used subject.

How to change this code to send an reply. Please Help me

Nisanth
  • 323
  • 8
  • 24

3 Answers3

4

You need to pass the thread id of the message you want to reply to and set the same subject for the new message. I prefer using some library for generating the raw string for the message, instead of writing it manually in order to minimize the possibility of errors. Below is an example using PHPMailer.

$gmail = new Google_Service_Gmail($client);
$message = new Google_Service_Gmail_Message();
$optParam = array();
$referenceId = '';
$thread = $gmail->users_threads->get($userId, $threadId);
$optParam['threadId'] = $threadId;
$threadMessages = $thread->getMessages($optParam);
$messageId = $threadMessages[0]->getId();
$messageDetails = $this->getMessageDetails($messageId); //omitted for simplicity: returns prepared message data.
$messageDetails = $messageDetails['data'];
$subject = $messageDetails['headers']['Subject'];
$mail = new PHPMailer();
$mail->CharSet = 'UTF-8';
$mail->From = $from_email;
$mail->FromName = $from_name;
$mail->addAddress($to);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->preSend();
$mime = $mail->getSentMIMEMessage();
$raw = $this->Base64UrlEncode($mime); //omitted for simplicity: Encodes the data in base 64 format for sending.
$message->setRaw($raw);
$message->setThreadId($threadId);
$response = $gmail->users_messages->send($userId, $message);

userId is the id of the logged in user, while threadId is the id of the thread of the message you want to reply to.

I've had a lot of difficulties with Google's PHP SDK and the lack of proper examples, so I wrote a PHP wrapper that covers most of the Gmail API's functions. It covers the explanation above, if you dig into it you'd find the logic that's omitted in the example above. You can find it here.

trajchevska
  • 942
  • 7
  • 13
  • Thanks for your reply . Is the above code need any plugins or library. – Nisanth Jul 22 '16 at 04:33
  • If you are using it with composer it will setup everything it needs itself. Otherwise, you need to manually do that. It uses Google's PHP SDK and PHPMailer. Going with composer would be better for loading the files as well. – trajchevska Jul 22 '16 at 06:42
  • i am trying this code for sending reply . how to pass the thread id in to this one $line = "\n"; $raw = "To: $to".$line; if(!empty($_POST['recc']) || !empty($_POST['rebcc'])){ $cc = $_POST['recc']; $bcc = $_POST['rebcc']; $raw .= "Cc: $cc". $line; $raw .= "Bcc: $bcc". $line; } $raw .= "Subject: $subject".$line.$line; $raw .= $message; $base64 = base64_encode($raw); $data = '{ "raw" : "'.$base64.'" }'; $send = Qassim_HTTP(1, $url, $header, $data); – Nisanth Jul 22 '16 at 06:53
  • `$this` is a core concept of object-oriented programming and refers to the object where we are making the call to the `getMessageDetails` method. To be able to implement this, you need a solid understanding of object-oriented programming. You can start with the basics [here](http://php.net/manual/en/language.oop5.basic.php) – trajchevska Dec 31 '17 at 19:44
  • 2
    @trajchevska I guess the question is more about: Why is this method being called from there? It expects a class-context. I guess that's a part of your mentioned wrapper-class. The line should be at least like this: $messageDetails = $gmail->users_messages->get($userId, $messageId); After that one of course has to extract required information from the returned object. – n.r. Aug 22 '18 at 13:05
  • 1
    @n.r. hmm, you're right, the answer is 2 years old, I didn't remember it :) It would add on complexity to the example if that part is included in the code: it should be replaced with the message details that are already prepared for sending. I'll add a comment, thanks for noting this! – trajchevska Aug 26 '18 at 15:55
  • @trajchevska - please also note, that I already took your code and extended with the missing functions, that will save you some time, i guess :) – n.r. Aug 27 '18 at 10:19
3

The above answer from @trajchevska is pretty nice and I am glad that I found it (!) - but it will not "reveal the full truth". So I tried to put together my insights to create a snippet that should work as-it-is.

$user = 'me'; // or user@example.com
$emailId = 12301839123180983123;
$from = 'johndoe@foobar.com';
$fromName = 'John Doe';

// this is for first authentification of this app to the Google-universe in general
$client = getClient();

// an this is to actually start working with Gmail
$googleService = new Google_Service_Gmail($client);

try {

    // receive the message body and extract it's headers
    $message = $googleService->users_messages->get($user, $emailId);
    $messageDetails = $message->getPayload();
    $messageHeaders = $messageDetails->getHeaders();

    // get the subject from the original message header
    $subject = 'Re:'.$getMessageHeaderValue($messageHeaders, 'Subject');

    // if you use the from header, this may contain the complete email address like John Doe <john.doe@foobar.com> - phpMailer will not accept that, the tricky thing is: you will not notice it, because it will be left blank and the Gmail API will return an "Recipient address required"
    preg_match('/.*<(.*@.*)>/', $getMessageHeaderValue($messageHeaders, 'From'),$to);

    // now use the PHPMailer to build a valid email-body
    $mail = new PHPMailer();
    $mail->CharSet = 'UTF-8';
    $mail->From = $from;
    $mail->FromName = $fromName;
    $mail->addAddress($to[1]);
    $mail->Subject = $subject;
    $mail->Body = $body;
    // preSend will build and verify the email
    $mail->preSend();

    $mime = $mail->getSentMIMEMessage();
    // the base64-url-encode is important, otherwise you'll receive an "Invalid value for ByteString" error
    $raw = base64url_encode($mime);

    // now use the Gmail-Message object to actually 
    // for me it is not clear, why we cannot use Class Google_Service_Gmail for this
    $message = new Google_Service_Gmail_Message();

    $message->setRaw($raw);

    $message->setThreadId($emailId);

    // and finally provide encoded message and user to our global google service object - this will send the email
    $response = $googleService->users_messages->send($user, $message);

} catch (Exception $e) {

    print($e->getMessage());

}

function getMessageHeaderValue($headers, $headerName) {

        foreach ($headers as $header) {

            if ($header->name == $headerName) {

                return $header->value;

            }
        }

        return NULL;
    }

// this function comes from https://developers.google.com/people/quickstart/php
/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient()
{
    // first get a credentials.json from here:
    // https://console.developers.google.com/apis/
    //
    // if you change scope or before first use, run the script on CLI
    // it will return an URL that you need to call 
    // which will return an access token that you can use for future use
    $client = new Google_Client();
    $client->setApplicationName('Gmail API');

    // see scopes: https://developers.google.com/gmail/api/auth/scopes
    $client->setScopes(array(Google_Service_Gmail::GMAIL_READONLY,Google_Service_GMail::GMAIL_COMPOSE));

    $client->setAuthConfig('credentials.json');

    $client->setAccessType('offline');

    // Load previously authorized credentials from a file.
    $credentialsPath = 'token.json';
    if (file_exists($credentialsPath)) {
        $accessToken = json_decode(file_get_contents($credentialsPath), true);
    } else {
        // Request authorization from the user.
        $authUrl = $client->createAuthUrl();
        printf("Open the following link in your browser:\n%s\n", $authUrl);
        print 'Enter verification code: ';
        $authCode = trim(fgets(STDIN));

        // Exchange authorization code for an access token.
        $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);

        // Store the credentials to disk.
        if (!file_exists(dirname($credentialsPath))) {
            mkdir(dirname($credentialsPath), 0700, true);
        }
        file_put_contents($credentialsPath, json_encode($accessToken));
        printf("Credentials saved to %s\n", $credentialsPath);
    }
    $client->setAccessToken($accessToken);

    // Refresh the token if it's expired.
    if ($client->isAccessTokenExpired()) {
        $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
        file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
    }
    return $client;
}

function base64url_encode($mime) {
    return rtrim(strtr(base64_encode($mime), '+/', '-_'), '=');
}
n.r.
  • 831
  • 1
  • 11
  • 30
0

As the original question is using the Raw method of Googles API there is in fact quite a simple solution. Gmail API uses RFC 2822 (https://datatracker.ietf.org/doc/html/rfc2822) and therefore you can simply using the following:

$strRawMessage .= "Reply-To: Test <test@test.com>\r\n";

Antony
  • 3,875
  • 30
  • 32