【问题标题】:Send email from PHP site through GMAIL API通过 GMAIL API 从 PHP 站点发送电子邮件
【发布时间】:2019-01-19 06:55:29
【问题描述】:

我有一个 PHP 网站,我从该网站向我们的客户发送通知电子邮件。 电子邮件是从我们的数据库中生成正文、收件人等的 html 表单发送的。

目前电子邮件是通过 PHP 邮件功能使用此代码发送的:

function SEND_MAIL($RECIPIENT,$EMAILSUBJECT,$EMAILBODY){
    $emailfrom = 'mail@blabla.com';
    $fromname = 'From name';
    $headers =
                'Return-Path: ' . $emailfrom . "\r\n" .
                'From: ' . $fromname . ' <' . $emailfrom . '>' . "\r\n" .
                'X-Priority: 3' . "\r\n" .
                'X-Mailer: PHP ' . phpversion() .  "\r\n" .
                'Reply-To: ' . $fromname . ' <' . $emailfrom . '>' . "\r\n" .
                'MIME-Version: 1.0' . "\r\n" .
                'Content-Transfer-Encoding: 8bit' . "\r\n" .
                'Content-Type: text/html; charset=ISO-8859-1' . "\r\n";
    $params = '-f ' . $emailfrom;
    $sendit = mail($RECIPIENT, $EMAILSUBJECT, $EMAILBODY, $headers, $params);
}

SEND_MAIL($CONTACTS_EMAIL,$EMAILSUBJECT_PERSON_A,$EMAILBODY_PERSON_A);

我们希望使用 GMAIL API 替换此功能,因为我们希望跟踪 GMAIL 帐户中发送的邮件。我们使用 Bluehost 作为提供者,因此无法使用到 GMAIL 服务器的 SMTP。 我们在很多地方都使用了这个函数,所以如果可能的话,我们更愿意修改那段代码。 我花了几天的时间试图让它发挥作用,最后我得到了一些结果。

到目前为止,我已经在 google 开发人员控制台中配置了所有内容,我能够运行 quickstart.php(如 in this tutorial 所述)。 使用本教程,我们上传了 JSON 文件,并且在设置了我们从 gmail 复制/粘贴的令牌后,我们可以访问 GMAIL 帐户的文件夹(标签)。

然后我可以使用我在网上找到的代码示例发送电子邮件

session_start();
 require __DIR__ . '/vendor/autoload.php';

  // Replace this with your Google Client ID
  $client_id     = 'blabla.apps.googleusercontent.com';
  $client_secret = 'secret';
  $redirect_uri  = 'https://www.redirecturl'; 

  $client = new Google_Client();
  $client->setClientId($client_id);
  $client->setClientSecret($client_secret);
  $client->setRedirectUri($redirect_uri);

  // We only need permissions to compose and send emails
  $client->addScope("https://www.googleapis.com/auth/gmail.compose");
  $service = new Google_Service_Gmail($client);

  // Redirect the URL after OAuth
  if (isset($_GET['code'])) {
    $client->authenticate($_GET['code']);
    $_SESSION['access_token'] = $client->getAccessToken();
    $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
  }

  // If Access Toket is not set, show the OAuth URL
  if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
    $client->setAccessToken($_SESSION['access_token']);
  } else {
    $authUrl = $client->createAuthUrl();
  }

  if ($client->getAccessToken() && isset($_POST['message'])) {

    $_SESSION['access_token'] = $client->getAccessToken();

    // Prepare the message in message/rfc822
    try {

        // The message needs to be encoded in Base64URL
        $emailad=$_POST['emailad'];
        $username=$_POST['username'];
        $emailbody=$_POST['emailbody'];

        $strSubject = $_POST['subject'];

        $strRawMessage = "From: fromname <fromemail>\r\n";
        $strRawMessage .= "To: $username <$emailad>\r\n";
        $strRawMessage .= 'Subject: =?utf-8?B?' . base64_encode($strSubject) . "?=\r\n";
        $strRawMessage .= "MIME-Version: 1.0\r\n";
        $strRawMessage .= "Content-Type: text/html; charset=utf-8\r\n";
        $strRawMessage .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n\r\n";
        $strRawMessage .= "$emailbody\r\n";

        $mime = rtrim(strtr(base64_encode($strRawMessage), '+/', '-_'), '=');
        $msg = new Google_Service_Gmail_Message();
        $msg->setRaw($mime);
        $service->users_messages->send("me", $msg);
    } catch (Exception $e) {
        print($e->getMessage());
        unset($_SESSION['access_token']);
    }
  } ?>
 <? if ( isset ( $authUrl ) ) { ?>
  <a href="<?= $authUrl; ?>"><img src="google.png" title="Sign-in with Google" /></a>
 <? } else { ?>
  <form method="POST" action="">
    <textarea name="emailbody" required></textarea>
    <input type="email" required name="emailad">
    <input type="text"  required name="subject">
    <input type="text"  required name="username">
    <input type="submit" value="submit">
  </form>
<? } ?>

最后一种方法还需要来自 google 的令牌,并且需要帐户访问权限。

所以我们想使用这两种方法之一来替换我们的 SEND_MAIL 函数。 我还想知道是否有可能永远不会使访问令牌过期,这样一旦我们允许访问,我们就不必通过 Gmail 接受程序。

感谢您的帮助!

【问题讨论】:

    标签: php gmail-api


    【解决方案1】:

    无法获得不会过期的访问令牌,但有一种方法可以获得所谓的刷新token。刷新令牌永不过期,并且在您取消对应用程序的授权之前一直可用。

    我使用了您提供的代码,并进行了一些小的调整和更改,我能够使用 Google Gmail API 发送电子邮件。刷新令牌和原始访问令牌的唯一缺点需要存储在数据库或文件中,以便 Google PHP API 可以查看令牌,但这限制了必须重新登录并重新授权您的应用程序的需要。

    身份验证文件——该文件只能使用一次。它是在数据库中设置令牌。设置令牌后,您可以从服务器中删除此文件。

    <?php
    require '/var/www/html/vendor/autoload.php'; // For Google Client Composer
    
    // Replace this with your Google Client ID
    $client_id     = 'blabla.apps.googleusercontent.com';
    $client_secret = 'secret';
    $redirect_uri  = 'https://www.redirecturl'; 
    
    $client = new Google_Client();
    $client->setClientId($client_id);
    $client->setClientSecret($client_secret);
    $client->setRedirectUri($redirect_uri);
    $client->setAccessType('offline'); //Added for Refresh Token
    $client->setApprovalPrompt('force'); //Added for Refresh Token
    
    // We only need permissions to compose and send emails
    $client->addScope("https://www.googleapis.com/auth/gmail.compose");
    
    // Redirect the URL after OAuth
    if (isset($_GET['code'])) {
      $client->authenticate($_GET['code']);
      $_SESSION['access_token'] = $client->getAccessToken();
    }
    
    // If Access Token is not set, show the OAuth URL
    if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
      $display = "display: none";
      $client->setAccessToken($_SESSION['access_token']);
    } else {
      $authUrl = $client->createAuthUrl();
    }
    
    $access_token = $client->getAccessToken();
    
    echo '<a href="'.$authUrl.'" style="'.$display.'">Authorize ME PLZ</a>';
    
    if ($access_token != null) {
      echo "You're In!";
    }
    
    // Saves Access Token Into Database to be Used In SEND_MAIL function
    $mysqli = new mysqli('servername', 'username', 'password', 'database');
    $stmt = $mysqli->prepare("INSERT INTO refresh_token (refresh, original) VALUES (?, ?)");
    $stmt->bind_param("ss", json_encode($access_token), json_encode($access_token)); // Updated to remove warning
    $stmt->execute();
    $stmt->close();
    ?>
    

    SEND_MAIL FUNCTION -- 从数据库中获取值以验证 Gmail API:

    <?php
    
    require '/var/www/html/vendor/autoload.php';
    
       function SEND_MAIL($RECIPIENT,$EMAILSUBJECT,$EMAILBODY){
    
          //Get Refresh Token From Database set when running Authentication File
          $conn = new mysqli("servername", "username", "password", 'database');
    
          $sql = "SELECT * FROM refresh_token";
          $result = $conn->query($sql);
          if ($result->num_rows > 0) {
              while($row = $result->fetch_assoc()) {
                 $token = $row['original'];
                 $refresh_token = $row['refresh'];
              }
          }
          $conn->close();
    
          // Replace this with your Google Client ID
          $client_id     = 'blabla.apps.googleusercontent.com';
          $client_secret = 'secret';
          $redirect_uri  = 'https://www.redirecturl'; 
    
          $client = new Google_Client();
          $client->setClientId($client_id);
          $client->setClientSecret($client_secret);
          $client->setRedirectUri($redirect_uri);
          $client->addScope("https://www.googleapis.com/auth/gmail.compose");
          $client->setAccessType('offline');
          $client->setApprovalPrompt('force');
    
          $client->setAccessToken($token);
    
          if ($client->isAccessTokenExpired()) {
          $client->refreshToken($refresh_token);
          $newtoken = $client->getAccessToken();
          $client->setAccessToken($newtoken);
          }
    
          $service = new Google_Service_Gmail($client);
    
          $fromemail = "<the-email-you-want-to-send-from>@gmail.com";
    
          $strRawMessage = "From: Email <$fromemail> \r\n";
          $strRawMessage .= "To: <$RECIPIENT>\r\n";
          $strRawMessage .= 'Subject: =?utf-8?B?' . base64_encode($EMAILSUBJECT) . "?=\r\n";
          $strRawMessage .= "MIME-Version: 1.0\r\n";
          $strRawMessage .= "Content-Type: text/html; charset=utf-8\r\n";
          $strRawMessage .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n\r\n";
          $strRawMessage .= "$EMAILBODY\r\n";
          $mime = rtrim(strtr(base64_encode($strRawMessage), '+/', '-_'), '=');
          $msg = new Google_Service_Gmail_Message();
          $msg->setRaw($mime);
          $service->users_messages->send("me", $msg);
       }
    
       SEND_MAIL('test@me.com', 'Test', 'Hey!');
    
       ?>
    

    【讨论】:

    • 非常感谢它的魅力。我只是收到一个小通知通知:未定义的索引:第 484 行的 /home2/pureseat/public_html/vendor/google/apiclient/src/Google/Client.php 中的 expires_in 根据信息,我发现这应该是问题所在: 当调用 $client->setAccessToken() 时,确保你传递了整个 json 字符串,而不仅仅是令牌部分。 json 字符串包含 expires_in 时间戳,在 isAccessTokenExpired 中评估
    • 太棒了,我已经更新了上面的代码,所以你将不再收到“通知:未定义的索引:”。我已经注意到我在哪里进行了更改。
    • 代码更新小错误:缺少end ) $stmt->bind_param("ss", json_encode($access_token), json_encode($access_token);
    • 啊,明白了。谢谢!
    • @Ian White,我已经实施了一段时间的代码。但是令牌过期后,我总是收到错误“无效的凭据”。所以我总是不得不重新运行第一个脚本来手动授权我。我可以在数据中看到令牌已更新,脚本可能有什么问题?谢谢
    猜你喜欢
    • 2019-01-24
    • 2014-10-30
    • 2020-01-06
    • 2012-01-07
    • 2023-03-19
    • 2017-05-25
    • 2016-07-19
    相关资源
    最近更新 更多