質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Gmail

GmailとはGoogleによって提供されているウェブメールのサービスのことです。

Google API

Googleは多種多様なAPIを提供していて、その多くはウェブ開発者向けのAPIです。それらのAPIは消費者に人気なGoogleのサービス(Google Maps, Google Earth, AdSense, Adwords, Google Apps,YouTube等)に基づいています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

1回答

543閲覧

GmailApi base64url文字列としてエンコードされたMIMEメールの作成方法についてアドバイスください

Amaryllis.

総合スコア8

Gmail

GmailとはGoogleによって提供されているウェブメールのサービスのことです。

Google API

Googleは多種多様なAPIを提供していて、その多くはウェブ開発者向けのAPIです。それらのAPIは消費者に人気なGoogleのサービス(Google Maps, Google Earth, AdSense, Adwords, Google Apps,YouTube等)に基づいています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2018/08/12 03:07

編集2018/08/19 22:46

前提・実現したいこと

はじめての質問なので至らない点があるかもしれませんがご了承ください。
作っているのはPHPにてお問い合わせフォームから情報を受け取り、Sheets Apiを使いそれをspreadsheetに記述、そしてGmail Apiを使用して返信メールを送信するというものです。
今の状況としましては、spreadsheetに記述するまではできたのですがメール作成の際にエラーが出てしまいました。
自分なりに解決しようと頑張っていましたがどうしても上手くいかずこうして皆さんのご助力を願う次第です。

試したこと

コードを書く際に公式のドキュメント
https://developers.google.com/gmail/api/guides/sending
https://developers.google.com/gmail/api/v1/reference/users/messages/send
を読みますと、
「RFC 2822に準拠し、base64url文字列としてエンコードされたMIMEメールをrawプロパティに設定してください。」
とありました。
ですが、「base64url文字列としてエンコードされたMIMEメール」の作成方法がわからなかったので、
https://stackoverflow.com/questions/34125436/php-create-mime-message-for-gmail-api
を参考にしました。
そこではメール作成にswift mailerを使うといいよと書いてありました。
しかし、swift mailerを使ってもmessageに対してBad Requestとエラーが出てしまい現状に至ります。

補足情報(バージョンなど)

XAMPP for Windows 7.2.7
"google/apiclient": "^2.0"
"swiftmailer/swiftmailer": "^6.0"

コード内の個人情報を含むものはxxxに変えてあります。

発生している問題・エラーメッセージ

Fatal error: Uncaught Google_Service_Exception: { "error": { "errors": [ { "domain": "global", "reason": "failedPrecondition", "message": "Bad Request" } ], "code": 400, "message": "Bad Request" } }

該当のソースコード

php

1<?php 2date_default_timezone_set('Asia/Tokyo'); 3$date = date('Y/ m/ d/ H:i:s'); 4$name = $_POST['name']; 5$mail = $_POST['mail']; 6$inquiry = $_POST['inquiry']; 7 8require __DIR__ .'\vendor\autoload.php'; 9 10putenv('GOOGLE_APPLICATION_CREDENTIALS='.dirname(__FILE__).'\xxx.json'); 11 12$client = new Google_Client(); 13$client -> useApplicationDefaultCredentials(); 14$client -> addScope(Google_Service_Sheets::SPREADSHEETS); 15$service = new Google_Service_Sheets($client); 16 17$spreadsheetId = 'xxx-xxx_xxx'; 18$sheetId = x; 19//ヘッダーの下に行を挿入 20$requestBody = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest(array( 21 'requests' => array( 22 'insertDimension' => array( 23 'range' => array( 24 'sheetId' => $sheetId, 25 'dimension' => 'ROWS', 26 'startIndex' => 1, 27 'endIndex' => 2 28 ), 29 'inheritFromBefore' => FALSE 30 ) 31 ) 32)); 33$response = $service -> spreadsheets -> batchUpdate($spreadsheetId, $requestBody); 34//スプレッドシートに書き込む 35$range = 'シート1!A1:D1'; 36$requestBody = new Google_Service_Sheets_ValueRange(array( 37 'values' => [array($date, $name, $mail, $inquiry)] 38)); 39$params = array('valueInputOption' => 'USER_ENTERED'); 40$response = $service -> spreadsheets_values -> append($spreadsheetId, $range, $requestBody, $params); 41 42//メール返信 43$client = new Google_Client(); 44$client -> useApplicationDefaultCredentials(); 45$client -> addScope(Google_Service_Gmail::GMAIL_SEND); 46 47$service = new Google_Service_Gmail($client); 48$userId = 'xxx@gmail.com'; 49 50$message = new Google_Service_Gmail_Message(); 51$msg = (new Swift_Message('お問い合わせありがとうございます')) 52 -> setFrom(['xxx@gmail.com' => '送信者名']) 53 -> setTo([$mail => 'お客様']) 54 -> setBody('この度はお問い合わせありがとうございます。'); 55$msg = rtrim(strtr(base64_encode($msg), '+/', '-_'), '='); 56$message -> setRaw($msg); 57$message = $service -> users_messages -> send($userId, $message); 58?> 59 60 <!DOCTYPE html> 61 <html lang="ja" dir="ltr"> 62 <head> 63 <meta charset="utf-8"> 64 <title>thanks</title> 65 </head> 66 <body> 67 <p>thanks!!</p> 68 </body> 69 </html>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

格闘の末、自己解決できたので記入しておきます。

分かってしまえば簡単なことで、単にユーザー認証がうまくいっていませんでした。
何が間違っていたかというと、エラーメッセージの"message": "Bad Request"に注目していましたが、本来のエラーは"reason": "failedPrecondition"でした。
failedPreconditionとは前提条件が失敗してるよとのことで、最初はなんのこっちゃと思っていましたが、下記のサイトを見てみると

このサイトから引用

Service accounts will only work with Gsuite email accounts.
The admin of the Gsuite (domain) account will have to grant the service account access to the users email account.
Unfortunately i don't have access to a Gsuite account so cant help you set it up. This might help Perform G Suite Domain-Wide Delegation of Authority
If this is a normal Gmail user account you are trying to access then you cant use a service account. You will either have to go though the SMTP / IMAP servers or using Oauth2 to authenticate the user.

GmailAPIにはサービスアカウント認証は使えないよと書かれていました。

個人でGmailAPIを利用するには下記の3つの認証方法のうち、
・APIキー
・OAuthクライアントID
・サービスアカウントキー
OAuthクライアントIDでの認証が必要でした。

ではOAuthクライアントIDでの認証をどうやってしたのかというと、
https://developers.google.com/identity/protocols/OAuth2WebServer?hl=ja
公式ドキュメントを参照してください。(そのまんまなので)

そして、この質問の趣旨であるMIMEメッセージの作成ですが、今はswiftmailerではなくpear/mail_mimeというパッケージをインストールして使っています。
pear/mail_mimeの使い方は、
https://github.com/gdgbhu/gmail-php-starter/blob/master/gmail.php
を参考にさせてもらいました。

最後に無事動作したコードを載せておきます。
コード内のxxxxは自分のに変えてください。
macやlinuxの人は\(バックスラッシュ)を/(スラッシュ)に変えるといいかもです。

PHP

1test-form.php 2 3<?php 4//外部ファイルの読み込み 5require_once __DIR__ .'\vendor\autoload.php'; 6 7session_start(); 8 9$client = new Google_Client(); 10$client -> setAuthConfig('client_secret.json'); 11$client -> addScope(Google_Service_Sheets::SPREADSHEETS); 12$client -> addScope(Google_Service_Gmail::GMAIL_SEND); 13 14if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { 15 $client -> setAccessToken($_SESSION['access_token']); 16 17 date_default_timezone_set('Asia/Tokyo'); 18 $date = date('Y/ m/ d/ H:i:s'); 19 $name = $_POST['name']; 20 $mailAddress = $_POST['mail']; 21 $inquiry = $_POST['inquiry']; 22 23 $service = new Google_Service_Sheets($client); 24 $spreadsheetId = 'xxxx-xxxx'; 25 $sheetId = x; 26 //ヘッダーの下に行を挿入 27 $requestBody = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest(array( 28 'requests' => array( 29 'insertDimension' => array( 30 'range' => array( 31 'sheetId' => $sheetId, 32 'dimension' => 'ROWS', 33 'startIndex' => 1, 34 'endIndex' => 2 35 ), 36 'inheritFromBefore' => FALSE 37 ) 38 ) 39 )); 40 $response = $service -> spreadsheets -> batchUpdate($spreadsheetId, $requestBody); 41 //スプレッドシートに書き込む 42 $range = 'シート1!A1:D1'; 43 $requestBody = new Google_Service_Sheets_ValueRange(array( 44 'values' => [array($date, $name, $mailAddress, $inquiry)] 45 )); 46 $params = array('valueInputOption' => 'USER_ENTERED'); 47 $response = $service -> spreadsheets_values -> append($spreadsheetId, $range, $requestBody, $params); 48 49//メール返信 50$service = new Google_Service_Gmail($client); 51 52$mime = new Mail_mime(); 53$mime -> addTo($mailAddress); 54$mime -> setSubject('Testing Gmail API'); 55$mime -> setTXTBody('This is a demo Email'); 56$mime -> setHTMLBody('This is an example <strong>HTML</strong> email'); 57$message_body = $mime -> getMessage(); 58$encoded_message = rtrim(strtr(base64_encode($message_body), '+/', '-_'), '='); 59 60$message = new Google_Service_Gmail_Message(); 61$message -> setRaw($encoded_message); 62$message = $service -> users_messages -> send('me', $message); 63 64} else { 65 $redirect_uri = 'http://localhost/xxxx/oauth2callback.php'; 66 header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); 67} 68?> 69 70 <!DOCTYPE html> 71 <html lang="ja" dir="ltr"> 72 <head> 73 <meta charset="utf-8"> 74 <title>thanks</title> 75 </head> 76 <body> 77 <p>thanks!!</p> 78 </body> 79 </html> 80

PHP

1oauth2callback.php 2 3<?php 4//外部ファイルの読み込み 5require_once __DIR__ .'\vendor\autoload.php'; 6 7session_start(); 8 9$client = new Google_Client(); 10$client -> setAuthConfigFile('client_secret.json'); 11$client -> setRedirectUri('http://localhost/xxxxx/oauth2callback.php'); 12$client -> addScope(Google_Service_Sheets::SPREADSHEETS); 13$client -> addScope(Google_Service_Gmail::GMAIL_SEND); 14 15if (! isset($_GET['code'])) { 16 $auth_url = $client -> createAuthUrl(); 17 header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL)); 18} else { 19 $client -> authenticate($_GET['code']); 20 $_SESSION['access_token'] = $client -> getAccessToken(); 21 $redirect_uri = 'http://localhost/xxxx/test-form.php'; 22 header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); 23} 24 ?>

投稿2018/08/19 23:46

Amaryllis.

総合スコア8

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Amaryllis.

2018/08/20 05:33

oauth2callback.phpの $client -> addScope(Google_Service_Gmail::GMAIL_SEND); の下に $client -> setAccessType('offline'); を追加してください。 30分たつとエラーが出てしまいます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問