目次
1. 概要
2. 追加機能の概要
3. ルート設定
4. メール送信クラスの作成
5. メール送信APIの作成
6. InquirySendMailメイラブルクラス編集
7. メール文面のビューの作成
8. APIで返却したメッセージを画面表示させる
9. おわりに
1. 概要
問い合わせフォームから、
問い合わせ内容をgmailで送信するロジックを説明します。
2. 追加機能の概要
-
お問い合わせページを追加
- ページURLは、/contact
- お名前、メールアドレス、タイトル、お問い合わせ内容を入力。
- SUBMITボタンを押す事で、ユーザーにgmail送信する。
-
お問い合わせ内容をgmailで送信(API)
- ポストメソッドの宛先URLは、/contact/thanks とする。
- InquiryController内で処理する。
- データベースへの保存はしない。
- メールを、管理者と問い合わせした人に送信する。
3. ルート設定
Route::controller(InquiryController::class)->group(function() {
Route::get('/contact', 'index');
});
対象ファイルは、 routes\web.php
/contact にGETメソッドでアクセスすると InquiryController.phpのindex()メソッドを呼び出し、お問い合わせ画面が表示される。
Route::controller(InquiryController::class)->group(function() {
Route::post('/contact/thanks', 'store');
});
対象ファイルは、 routes\api.php
同様に、/contact/thanks にPOSTメソッドでアクセス(SUBMITボタン押下)すると、同じInquiryController.phpのstore()メソッドを呼び出す。
4. メール送信クラスの作成
laravelではメール送信するためにMailable(メイラブル)クラスを作成する。
Mailableとメール送信の方法について詳しくは以下参照。
Mailableクラスは、artisan makeコマンドで作成できる。
php artisan make:mail InquirySendMail
対象 app\Mail\InquirySendMail.php
→このファイルとMailファサードのtoメソッド使って、メールを送信する。
設定ファイルにメールサーバーの情報を入力する。
gmailのメールアカウントとSMTPサーバーを使ってメールを送信する。
gmailでメール送信するため、以下手順が必要。
- gmailで2段階認証の設定。
- アプリパスワードの発行。
- SMTPサーバーの設定を
.env
に追加。
(参考:https://qiita.com/hiro5963/items/df062ab19e8ceba4573f)
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=admin@gmail.com // 自身のgmailを設定。
MAIL_PASSWORD=アプリパスワード // 2で作成したアプリパスワードを記載。
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="admin@gmail.com" // 自身のgmailを設定。
→ローカル環境でgmail送信のテストを行いたい場合は、環境設定ファイル.env
に上記を設定する。
5. メール送信APIの作成
対象は app\Http\Controllers\InquiryController.php
use App\Mail\InquirySendMail;
use Illuminate\Support\Facades\Mail;
MailファサードとInquirySendMailメイラブルクラスを使用するので、use文を記述する。
storeメソッド
/**
* inquiry store
*
* @param Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'name' => 'required',
'email' => 'required|email',
]);
Mail::send(new InquirySendmail($request));
// 再送信を防ぐためにトークンを再発行
$request->session()->regenerateToken();
return response(
[
'result' => true,
'message' => 'ありがとうございます。メッセージが送信されました。',
'csrf_token' => $request->session()->token(),
],
);
}
-
api.php
に定義した、メール送信APIにて呼び出されるメソッド。 - お名前、メールアドレスは必須入力のバリデーションを指定。
- 入力データのバリデーションを行った後、MailファサードとInquirySendMailクラスを使用して、メールを送っている。
-
Mail::
の部分がMailファサード。(sendメソッドを呼び出している。) - sendメソッドでは、InquirySendMailクラスで作成するメール内容を実際に送信している。
- ※
$request->session()->regenerateToken();
は、view側で作成したcsrf_tokenを再発行する事で、お問い合わせの2重送信を防いでいる。
laravelは、csrf_token(クロス・サイト・リクエスト・フォージェリ(CSRF)から、アプリケーションを簡単に守ること) を発行する事が出来、Postリクエストを送る際は、以下のように「@csrf」を記載しないとエラーが発生する。
// metaタグにその値を保存しておく。
<meta name="csrf-token" content="{{ csrf_token() }}">
...略
<form method="POST">
@csrf
...
</form>
6. InquirySendMailメイラブルクラス編集
全体コード
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Http\Request;
use Illuminate\Queue\SerializesModels;
class InquirySendmail extends Mailable
{
use Queueable, SerializesModels;
private $name;
private $email;
private $title;
private $body;
/**
* Create a new message instance.
*
* @param Request $request
* @return void
*/
public function __construct(Request $request)
{
$this->name = $request->get('name');
$this->email = $request->get('email');
$this->title = $request->get('title');
$this->body = $request->get('body');
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$mail_admin = config('mail.from.address');
return $this
->from($mail_admin, '自身の名前')
->to($this->email)
->bcc($mail_admin)
->subject('お問い合わせを受け付けました')
->text('inquiry.mail')
->with([
'name' => $this->name,
'email' => $this->email,
'title' => $this->title,
'body' => $this->body,
]);
}
}
バリデート済みのデータを受け取るので、Requestクラスごと受け取る。
public function __construct(Request $request)
{
$this->name = $request->get('name');
$this->email = $request->get('email');
$this->title = $request->get('title');
$this->body = $request->get('body');
}
$this->
が、このクラス内のデータで、constructメソッドの引数が受け渡される仮引数。
public function build()
{
$mail_admin = config('mail.from.address');
return $this
->from($mail_admin, '自身の名前')
->to($this->email)
->bcc($mail_admin)
->subject('お問い合わせを受け付けました')
->text('inquiry.mail')
->with([
'name' => $this->name,
'email' => $this->email,
'title' => $this->title,
'body' => $this->body,
]);
}
resources\views\mail\mail.blade.php
をビューとして指定する。
->演算子(アロー演算子)でつなげて、text
メソッドで、ビューにデータを渡す。キーが’name’なのでviewの中で$name
という名前で参照することができる。
さらに、アロー演算子で subjectメソッドをつなげることで、メールの表題を設定することができる。
7. メール文面のビューの作成
メール文面は、 resources\views\mail\mail.blade.php
を指定。
{{ $name }} さま
お問い合わせいただき、
ありがとうございます。
【お問い合わせ内容】
お名前 : {{ $name }}
メール : {{ $email }}
タイトル : {{ $title }}
内 容 :
{!! $body !!}
$name
等で渡されたデータを{{ }}
内にて表示。
8. APIで返却したメッセージを画面表示させる。
- ajaxを用いて、非同期でメール送信APIを呼び出す。
→jqueryを使用する。
対象app\public\js\contact_ajax.js
初期状態では、レスポンスメッセージ表示用クラスを非表示にしておく
$(function () {
$(".response-output").hide();
....以下略
1行目の$(function(){
では、即時関数を宣言している。.response-output
は、htmlの親要素。(後のajax処理で、子要素を追加する。)
送信ボタンが押された時だけ、API通信を開始する。
$(function () {
$(".response-output").hide();
$("#submit-button").click(function () {
$(".response-output").hide();
$(".success-response").remove();
$(".error-response").remove();
....以下略
メッセージの画面表示有無に関わらず、最初にhide()で要素を隠し、removeで要素を削除する。
→メッセージはjqueryのアニメーションでスライド表示させる為、hide()で隠す。
→ボタン多重押下時に、メッセージが重複して表示されるのを防ぐための対応。
form入力データを取得し、変数に代入する
var name = $("input[name=your-name]").val();
var email = $("input[name=your-email]").val();
var title = $("input[name=your-title]").val();
var body = $("textarea[name=your-body]").val();
$.ajaxメソッドで通信を行う。
$.ajax({
headers: {
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
},
type: "POST",
dataType: "json",
url: "api/contact/thanks",
timeout: 30000,
data: { name: name, email: email, title: title, body: body },
})
.done((data) => {
})
.fail((data) => {
});
-
headers
は、リクエスト時に送信するヘッダー。
Ajax通信でも同様に、X-CSRF-TOKENを含めないと419エラーが発生するため、headerに含める必要がある。 -
type
は通信に利用するHTTPメソッド(今回はメール送信なので、POST) -
dataType
は、応答データの種類(レスポンスはjson型の為、’json’を指定) -
url
は、アクセス先のパス(inquiryController@storeメソッドにアクセスする。) -
timeout
は、指定秒数を経過しても通信が完了しない場合、エラー処理が実行される。 -
data
は、inquiryController@storeメソッドに送信するデータ(form入力値) -
done
は、通信に成功した時に実行される。 -
fail
は、通信に失敗した時に実行される。
API通信成功時、サクセスメッセージを表示させる
.done((data) => {
$(".response-output")
.append(
'<p class="success-response">' + data.message + '</p>'
)
.slideDown();
})
-
data
はサーバーが返すデータで、お問い合わせAPIのレスポンスメッセージは、data.
キーで取得できる。 - 「
data.message
」response-output
というhtmlの親要素に、append()
でレスポンスメッセージを表示させるための子要素を追加している。 - 親要素は、
hide()
で隠しておいたので、.slideDown()
で追加した子要素をスライド表示させる事ができる。
API通信失敗時、アラートメッセージを表示させる
.fail((data) => {
var error_text = "入力内容に問題があります。確認して再度お試しください。";
if (data.statusText == "timeout") {
error_text = "通信に失敗しました。画面を更新して再度お試しください。";
}
$(".response-output")
.append(
'<p class="error-response">' + error_text + '</p>'
)
.slideDown();
});
- ajax通信が、30秒経っても成功しない場合は、error_textの中身を変更して親要素に追加する。
全体コード
$(function () {
$(".response-output").hide();
$("#submit-button").click(function () {
$(".response-output").hide();
$(".success-response").remove();
$(".error-response").remove();
var name = $("input[name=your-name]").val();
var email = $("input[name=your-email]").val();
var title = $("input[name=your-title]").val();
var body = $("textarea[name=your-body]").val();
$.ajax({
headers: {
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
},
type: "POST",
dataType: "json",
url: "api/contact/thanks",
timeout: 30000,
data: { name: name, email: email, title: title, body: body },
})
.done((data) => {
$(".response-output")
.append(
'<p class="success-response">' + data.message + '</p>'
)
.slideDown();
})
.fail((data) => {
var error_text = "入力内容に問題があります。確認して再度お試しください。";
if (data.statusText == "timeout") {
error_text = "通信に失敗しました。画面を更新して再度お試しください。";
}
$(".response-output")
.append(
'<p class="error-response">' + error_text + '</p>'
)
.slideDown();
});
});
});
9. おわりに
上記手順で非同期にメール送信APIを実行できます。
今回、詳細なviewは記載していないので、お任せでお願いします。
環境によってうまく動かない場合があると思いますが、あくまでも自身のアウトプットのためにまとめており、誰かの参考程度になれば嬉しいな程度のため、ご理解いただけますと幸いです。