web開発

laravel5.6で確認画面付きお問い合わせメール機能実装する【コード例あり】

こんにちは。もんしょー(@sima199407)です。

メール送信を実装したい人
メール送信を実装したい人
Laravelでメール実装の方法教えてくださいー!

という質問があるかと思います。

今回は、Laravel5.6を使ったメール実装の方法についてご紹介でして、その中でもお問い合わせのためのフォームの作り方になります。

最近はWebサイトを作るときにGoogleフォームを使って、コードを貼り付けるだけでかんたんに実装できるようになりましたが、自由度の高い独自のフォームを作ること機会があるかと思います。

では早速見ていきましょう!

開発環境

今回使う環境は以下の通り。

・Laravel5.6
・docker
・Nginx
・MacOS
・mailtrap

MacOSの環境でdockerで仮想環境を作り、Laravelを動かしていきます。

もし環境設定が必要な方は「macにdockerでlaravelの環境構築をしてみた【やり方・つまづきやすいポイント】」で解説していますので読んでみてください。

最後のmailtrapというはテスト用のメールサーバーになります。

「本番用のサーバーを使って作業する前にテストしたい!」という人はぜひ使ってみてください。

使い方についてもこのページで説明します。

メール機能の実装方法

メール機能の実装は以下の方法で行います。

マイグレーションファイル作成
ルートを作成
コントローラー
モデル
viewファイル
リクエスト←作る理由は?
mailableクラスを作成

という流れでやっていこうと思います。

完成図

・ 名前
・ メールアドレス
・ 内容

とシンプルな形にします。

マイグレーションファイル作成

まずはDBの型を作っていきます

$ php artisan make:migration create_contacts_table --create=contacts

ファイル名は[create_contacts_table]にしまして、[–create=contacts]でDBのテーブル名をcontactsに指定します。

そして、/database/migrations/に移動して上記で作成したファイルを編集します。

/database/migrations/create_contacts_table
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

 
class CreateContactsTable extends Migration
{
    public function up()

    {
        Schema::create('contacts', function (Blueprint $table) {

            $table->increments('id');
            $table->string('name');
            $table->string('email');
            $table->text('body');
            $table->timestamps();
        });
    }
    public function down()

    {
        Schema::dropIfExists('contacts');
    }
}

こんな感じです。

[$table->]には必要最低限のデータしか入れてません。

件名や電話番号を入れたいときは、string型などで追記すれば増やすことができます。

~
$table->string(’title’);
$table->string(’tel');
~

ルート作成

ついでにルートも作っておきましょう。

routes/web.php

Route::get('contact', 'ContactController@index');
Route::post('contact/confirm', 'ContactController@confirm');
Route::post('contact/complete', 'ContactController@complete');

確認画面もつけておくので、confirmルートもつけておきましょう!

Controllers作成

まず、型となるファイルをコマンドで作成します。

$ php artisan make:controller ContactController --model=Contact

オプション[–model]をつけることでモデルも一緒に作成します。

こんなふうに聞かれますので、「yes」と入力

$ php artisan make:controller ContactController --model=Contact
 A App\Contact model does not exist. Do you want to generate it? (yes/no) [yes]:
 > yes

Model created successfully.
Controller created successfully.

そして ContactControllerを以下のように編集します。

とりあえず、indexのみを作成します。

app/Http/Controllers/ContactController.php

class ContactController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
 
        return view('contacts.index');
    }

Model作成

先程Controllersを作ったときに一緒に作成したModelファイルも編集します。

ここでは,protected $fillable = []を使って、扱ってもいいデータの名前を入れます。これをホワイトリスト形式といいます。
※fillable→代入可能という意味。

app/Contact.php

<?php
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Contact extends Model
{
    protected $fillable = [
        'name', 'email', 'body'
    ];
}

name,email,bodyは必須項目に設定しておきます。

モデルにはファイル名の付け方に条件がありましてそれが
・最初を大文字
・単数形
という条件がありますので気をつけましょう。

View作成

ではフロンド部分にあたるViewを作っていきましょう。
そのときにviewファイルをまとめておきたいので、viewディレクトリ直下にcontactsディレクトリを作成します。

$ cd resources/views 
$ mkdir contacts 

resources/views/contacts/index.blade.php


<div class="container">
            <div class="col-12">
                <h2 class="text-center page-title">お問い合わせ</h2>
            </div>
                
@if ($errors->any())
    <div class="alert alert-danger">
                    <ul>
                        @foreach ($errors->all() as $error)
                            <li>{{ $error }}</li>
                        @endforeach
                    </ul>
    </div>
@endif


                {!! Form::open(['url' => 'contact/confirm','class' => 'form-horizontal']) !!}
                <div class="row">
                    <!-- form1 -->
                <div class="col-12 form-group{{ $errors->has('name') ? ' has-error' :''}}">              
                    <div class="offset-md-3 col-sm-5 col-md-4">
                            {!! Form::label('name', 'お名前(もしくは企業名):', ['class' => 'sizeM control-label']) !!}
                        </div>
                        <div class="offset-md-3 col-sm-7 col-md-6">
                        {!! Form::text('name', null, ['class' => 'form-control']) !!}
                        </div>       
                    @if ($errors->has('name'))
                        <span class="help-block">
                            <strong>{{ $errors->first('name') }}</strong>
                        </span>
                    @endif
                    </div>
                    <!-- form2 -->
                    <div class="col-12 form-group{{ $errors->has('email') ? ' has-error' :''}}">
                           <div class="offset-md-3 col-sm-5 col-md-4">
                                {!! Form::label('email', 'メールアドレス:', ['class' => 'sizeM control-label']) !!}
                            </div>
                            <div class="offset-md-3 col-sm-7 col-md-6">
                            {!! Form::email('email', null, ['class' => 'form-control']) !!}
                            </div>  
                            @if ($errors->has('email'))
                                <span class="help-block">
                                    <strong>{{ $errors->first('email') }}</strong>
                                </span>
                            @endif
                            </div>
                    <!-- form3 -->
                        <div class="col-12 form-group{{ $errors->has('body') ? ' has-error' :''}}">       
                            <div class="offset-md-3 col-sm-5 col-md-4">
                                {!! Form::label('body', '内容:', ['class' => 'sizeM control-label']) !!}
                            </div>
                            <div class="offset-md-3 col-sm-7 col-md-6">
                                {!! Form::textarea('body', null, ['class' => 'form-control']) !!}
                            </div>
                            @if ($errors->has('body'))
                                <span class="help-block"><strong>{{ $errors->first('body') }}</strong>
                            </span>@endif
                        </div>
                    </div> 
                    <div class="col-12 form-group text-center">
                        {!! Form::submit('確認', ['class' => 'btn-lg btn-primary']) !!}
                    </div>
                    {!! Form::close() !!}
    </div>

Request作成

次にリクエストの作成です。あまり聞き慣れないかもしれませんが、バリデーションをするためにこのファイルをつかいます。

$ php artisan make:request ContactRequest

app/Http/Requests/ContactRequest.php

<?php
namespace App\Http\Requests;
 
use Illuminate\Foundation\Http\FormRequest;
 
class ContactRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }
    public function rules()
    {
        return [
            'name' => 'required|max:10',
            'email' => 'required|email',
            'body' => 'required|max:1000'
        ];
    }
    public function attributes() {
        return [
            'name' => 'お名前',
            'email' => 'メールアドレス',
            'body' => '内容'
        ];
    }
}

文字数の制限やemail形式なっているかどうかも判断してます。
そしてこのRequestはControllerファイルで使うことができます。
以下のような感じで使いますので、ContactController.phpを編集してます。

app/Http/Controllers/ContactController.php

public function index()
    {
 
        return view('contacts.index');
    }

    public function confirm(ContactRequest $request)
    {
    $contact = new Contact($request->all());
 
    return view('contacts.confirm');
    }


    // 保存
    public function complete(ContactRequest $request)
    {
    $input = $request->except('action');
     
    if ($request->action === '戻る') {
        return redirect()->action('ContactController@index')->withInput($input);
    }
 
    // データを保存
    Contact::create($request->all());
 
    // 二重送信防止
    $request->session()->regenerateToken();
         
    return view('contacts.complete');


    $name = $request->name;
    $body = $request->body;
    $to = $request->email;
    // $bcc = 'bcc@mail.com';
        
    Mail::to($request->email)
        // ->bcc('test@bcc.com')
        ->send(new \App\Mail\Contact($name, $body));
    }

使うのはファンクションの一番最初ですね。

function complete(ContactRequest $request)
→function FUNCTIONNAME(Requestファイル名 $request)

こんな感じで、Requestを使っていきます。

ちなみにバリデーションから通過したデータはどうやって受け取る方法は
[$request->all()]で受け取ることができます。

送信メールでCCやBCCを送る方法は1行追加してあげればOKです

Mail::to($request->email)  
->bcc('test@bcc.com') 
->send(new \App\Mail\Contact($name, $body));

ここまでで一連の流れを作ることができました。
次に実際にメールを送るテストも行っていきましょう。

メール送信設定

ターミナルでartisanコマンドを叩きましょう。

$ php artisan make:mail Contact

ファイルを編集していきましょう。
app/Mail/Contact.php

<?php
namespace App\Mail;
 
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
 
class Contact extends Mailable
{
    use Queueable, SerializesModels;

    protected $title;
    protected $body;

    public function __construct($name, $body)
    {
        $this->title = sprintf('%s様、お問い合わせありがとうございます', $name);
        $this->body = $body;
    }


    public function build()
    {
        return $this->view('email.to')
                    ->subject($this->title)
                    ->with([
                        'body' => $this->body,
                      ]);
    }
}

メールの本文を作ってみると以下通りにします。
resources/views/email/to.blade.php

<div>この度はお問い合わせありがとうございます。</div>
<div>下記の内容で受付致しました。</div>


<div>【名前】</div>
<div>{{$_POST['name']}}</div>
<div>【お問い合わせ内容】</div>
<div>{{$_POST['body']}}</div>

ここまででLaravel側の設定は終了です。

送信者情報を追加してテスト送信を行う

Laravelでの設定が終わったら、送信するための情報を設定しましょう。
envファイルから追加することができるので確認します。
必要な情報は以下の通り

./env

MAIL_DRIVER=smtp
MAIL_HOST=HOSTNAME
MAIL_PORT=2525
MAIL_USERNAME=USERNAME
MAIL_PASSWORD=PASSWORD
MAIL_FROM_ADDRESS=YOURTEST@YOURTEST.com //送信アドレス
MAIL_FROM_NAME=Example

メールサーバーに書いてある情報を使えばオッケーです。

mailtapを使ってみよう

とりあえずテストするんだったら無料のテストメールサーバー、mailtapが便利です。
開発環境でメール送信するときはこちらを使いましょう。

登録ができたら「SMTP Settings」→「Integrations」を探して、「laravel」を選択するとenvファイルにコピペする内容がでてきます。

それをenvファイルにコピペすればオッケーです。

まとめ

ここまでお疲れさまでした!

これでシンプルなメール送信機能が完成しました。

お役にたてば幸いです。

参考:https://www.ritolab.com/entry/38