0. はじめに
大阪のLaravel初学者サウナーこと、kazumakishimoto(@kazuma_dev)です!
Sendgrid
でLaravelのお問い合わせフォームの作り方です!
0-1. 全体の流れ
0-2. 本記事の対象者
- SendgridでLaravelのお問い合わせフォームを作成したい方
0-3. 事前準備
- Sendgridアカウント
- Gmailアカウント
0-4. 要件
- Sendgrid登録
- Sendgridを.env記載
- Laravel実装
0-5. 使用画像のイメージ
1. Sendgrid
- 下記参考にAPIKEY作成(※編集中)
2. Laravel
2-1. .env
# Sendgrid
MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=SG.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MAIL_ENCRYPTION=tls
MAIL_FROM_NAME="${APP_NAME}"
MAIL_FROM_ADDRESS=hoge@gmail.com
2-2. Route
routes/web.php
# お問い合わせ
// 入力ページ
Route::get('/contact', 'ContactController@index')->name('contact.index');
// 確認ページ
Route::post('/contact/confirm', 'ContactController@confirm')->name('contact.confirm');
// 送信完了ページ
Route::post('/contact/thanks', 'ContactController@send')->name('contact.send');
2-3. Controller
app/Http/Controllers/ContactController.php
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ContactRequest;
use App\Mail\ContactSendmail;
class ContactController extends Controller
{
public function index()
{
return view('contact.index');
}
public function confirm(ContactRequest $request)
{
$inputs = $request->all();
$data = [
'inputs' => $inputs,
];
return view('contact.confirm', $data);
}
public function send(ContactRequest $request)
{
$inputs = $request->all();
if ($request->has("back")) {
return redirect()->route('contact.index')
->withInput($inputs);
}
\Mail::to('grfl.official@gmail.com')->send(new ContactSendmail($inputs));
$request->session()->regenerateToken();
return view('contact.thanks');
}
}
2-4. ContactRequest
app/Http/Requests/ContactRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ContactRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|max:15',
'email' => 'required|email:strict,dns|max:255',
'title' => 'nullable|string|max:255',
'body' => 'required|string|max:1000',
];
}
public function attributes()
{
return [
'name' => 'お名前',
'email' => 'メールアドレス',
'title' => '件名',
'body' => 'お問い合わせ内容',
];
}
}
2-5. View
2-5-1. index.blade.php
resources/views/contact/index.blade.php
@extends('app')
@section('title', 'お問い合わせ - grfl')
@section('content')
@include('nav')
<header>
<div>
<div class="container" style="max-width: 900px;">
<nav aria-label="breadcrumb">
<ol class="breadcrumb bg-white small pl-0 mb-0">
<li class="breadcrumb-item">
<a href="/" class="text-teal1">grfl</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
お問い合わせ
</li>
</ol>
</nav>
</div>
</div>
</header>
<main>
<div class="bg-paper my-3">
<div class="container p-0" style="max-width: 540px">
<h4 class="text-center">
お問い合わせ
</h4>
<p style="font-size: 14px;">
grflに対するご意見・ご感想・お問い合わせなどございましたらお聞かせください。<br>
お送りいただいた内容はすべて確認しておりますが、ご返信を差し上げることができない場合もございますので、ご了承ください。
</p>
@if (session('status'))
<div class="card-text alert alert-success">
{{ session('status') }}
</div>
@endif
<div class="card shadow-sm mb-4">
<div class="card-body">
@include('error_card_list')
<form method="post" action="{{ route('contact.confirm') }}">
@csrf
<p class="small">
(<span class="text-danger">*</span>は必須項目です)
</p>
<div class="form-group">
<label for="name">お名前</label>
<span class="text-danger">*</span>
<input class="form-control" type="text" id="name" name="name" required value="{{ Auth::user()->name ?? old('name') }}">
</div>
<div class="form-group">
<label for="email">メールアドレス</label>
<span class="text-danger">*</span>
<input class="form-control" type="email" id="email" name="email" required value="{{ Auth::user()->email ?? old('email') }}">
</div>
<div class="form-group">
<label for="title">ご用件</label>
<input class="form-control" type="title" id="title" name="title" value="{{ old('title') }}">
</div>
<div class="form-group">
<label for="body">お問い合わせ内容</label>
<span class="text-danger">*</span>
<textarea type="text" name="body" id="body" rows="5" class="form-control" required>{{ old('body') }}</textarea>
<p class="text-muted small ml-1">1000文字以内</p>
</div>
<label for="agree" class="small" role="button">
<span class="d-flex flex-wrap">
<span>
<input type="checkbox" id="agree" required>
<a href="{{ route('privacy') }}" class="text-teal1 ml-2" target="_blank" title="プライバシーポリシーをブラウザの別画面で開く">プライバシーポリシー</a>
<span>を確認し、</span>
</span>
<span>同意</span>
<span>
<span>
<span>しました。</span><span class="text-danger">*</span>
</span>
</span>
</span>
</label>
<button type="submit" class="btn btn-block bg-white btn-outline-teal1 text-decoration-none text-teal1 mt-4">
<b>送信内容を確認する</b>
</button>
</form>
</div>
</div>
</div>
</div>
</main>
@include('footer')
@endsection
2-5-2. confirm.blade.php
resources/views/contact/confirm.blade.php
@extends('app')
@section('title', 'お問い合わせ内容の確認 - grfl')
@section('content')
@include('nav')
<main>
<div class="bg-paper my-3">
<div class="container p-0" style="max-width: 540px">
<h4 class="text-center">
お問い合わせ内容の確認
</h4>
<div class="card shadow-sm mb-4">
<div class="card-body">
<form method="post" action="{{ route('contact.send') }}">
@csrf
<div class="form-group">
<label for="name" class="text-muted">
お名前
</label>
<p>
{{ $inputs['name'] }}
</p>
<input name="name" value="{{ $inputs['name'] }}" type="hidden">
</div>
<div class="form-group">
<label for="email" class="text-muted">
メールアドレス
</label>
<p>
{{ $inputs['email'] }}
</p>
<input name="email" value="{{ $inputs['email'] }}" type="hidden">
</div>
<div class="form-group">
<label for="title" class="text-muted">
ご用件
</label>
<p>
@if ($inputs['title'] !== null)
{{ $inputs['title'] }}
@else
無題
@endif
</p>
<input name="title" value="{{ $inputs['title'] }}" type="hidden">
</div>
<div class="form-group">
<label for="body" class="text-muted">
お問い合わせ内容
</label>
<p>
{!! nl2br(e($inputs['body'], false)) !!}
</p>
<input name="body" value="{{ $inputs['body'] }}" type="hidden">
</div>
<button type="submit" name="back" value="back" class="btn btn-block btn-teal1 mt-4">
入力内容修正
</button>
<button type="submit" name="action" value="submit" class="btn btn-block bg-white btn-outline-secondary text-decoration-none text-secondary mt-4">
送信する
</button>
</form>
</div>
</div>
</div>
</div>
</main>
@include('footer')
@endsection
2-5-3. thanks.blade.php
resources/views/contact/thanks.blade.php
@extends('app')
@section('title', 'お問い合わせメール送信完了- grfl')
@section('content')
@include('nav')
<main>
<div class="bg-paper my-3">
<div class="container p-0" style="max-width: 540px">
<h4 class="text-center">お問い合わせ:送信完了</h4>
<div class="alert alert-info" role="alert">
<h5>
お問い合わせメールが送信されました!
</h5>
<a class="text-decoration-none text-info" href="/">
ホームへ戻る<i class="fas fa-chevron-circle-right ml-1"></i>
</a>
</div>
</div>
</div>
</main>
@include('footer')
@endsection
2-5-4. mail.blade.php
resources/views/contact/mail.blade.php
お問い合わせメールを受け付けました。<br>
<br>
■お名前<br>
{!! $name !!}<br>
<br>
■メールアドレス<br>
{!! $email !!}<br>
<br>
■タイトル<br>
@if ($title !== null)
{!! $title !!}<br>
@else
無題<br>
@endif
<br>
■お問い合わせ内容<br>
{!! nl2br($body) !!}<br>
補足
開発環境(FW/ツールのバージョンなど)
ツール | バージョン |
---|---|
Vue.js | 2.6.14 |
jQuery | 3.4.1 |
PHP | 7.4.1 |
Laravel | 6.20.43 |
MySQL | 5.7.36 |
Nginx | 1.18.0 |
Composer | 2.0.14 |
npm | 6.14.6 |
Git | 2.33.1 |
Docker | 20.10.11 |
docker-compose | v2.2.1 |
PHPUnit | 8.0 |
CircleCI | 2.1 |
heroku | 7.59.4 |
MacBook Air | M1,2020 |
macOS | Monterey 12.3 |
Homebrew | 3.3.8 |
ディレクトリ構造
【ルートディレクトリ】
├─ .circleci
│ └─ config.yml
├─ aws / CloudFormation
│ └─ ec2.yml
├─ docker
│ └─ mysql
│ └─ nginx
│ └─ php
│ └─ phpmyadmin
├─ src
│ └─ 【Laravelのパッケージ】
└─ docker-compose.yml
Reference