ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Mail(메일)
    Laravel 2020. 11. 1. 19:12
    반응형
    SMALL

    # .env 설정

    MAIL_MAILER=smtp
    MAIL_HOST=smtp.mailtrap.io
    MAIL_PORT=2525
    MAIL_USERNAME=null
    MAIL_PASSWORD=null
    MAIL_ENCRYPTION=null
    MAIL_FROM_ADDRESS=null
    MAIL_FROM_NAME="${APP_NAME}"

     

    # 메일 템플릿 생성

    php artisan make:mail PasswordResetCreated --markdown=emails.passwordResets.created

    @ PasswordReset.php

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    
    class PasswordReset extends Model
    {
        use HasFactory;
    
        protected $fillable = ["email", "token"];
    
        protected $primaryKey = "email";
    
        public $timestamps = false;
    
        public function resetUrl()
        {
            return config("app.url")."/passwordResets/$this->token/edit";
        }
    }

    @ PasswordResetCreated.php

    <?php
    
    namespace App\Mail;
    
    use App\Models\PasswordReset;
    use App\Models\User;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Mail\Mailable;
    use Illuminate\Queue\SerializesModels;
    
    class PasswordResetCreated extends Mailable
    {
        use Queueable, SerializesModels;
    
        protected $receiver;
    
        protected $passwordReset;
    
        /**
         * Create a new message instance.
         *
         * @return void
         */
        public function __construct(User $receiver, PasswordReset $passwordReset)
        {
            $this->receiver = $receiver;
    
            $this->passwordReset = $passwordReset;
        }
    
        /**
         * Build the message.
         *
         * @return $this
         */
        public function build()
        {
            return $this->markdown('emails.passwordResets.created')
                    ->subject("[".config("app.name")."] ".__("socialLogin.passwordReset")["send"])
                    ->with(["receiver" => $this->receiver, "passwordReset" => $this->passwordReset]);
        }
    }

     

    # 메일 기본 템플릿 커스텀하기

    php artisan vendor:publish --tag=laravel-mail

    * html은 resources/views/vendor/mail/html의 layout, footer, header, message 등을 고치면 됨.

    (내가 markdown으로 새로 만든 메일 view가 message.blade.php의 $slot 내용으로 들어가는거임)

     

    * css는 resources/views/vendor/mail/html/themes/default.css를 수정

     

    @ default.css

    @charset "utf-8";
    @import url(https://fonts.googleapis.com/earlyaccess/notosanskr.css);
    
    html {margin:0;padding:0;}
    body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,address,big,cite,code,del,dfn,em,font,img,ins,q,s,samp,small,strike,sub,sup,tt,var,b,u,i,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,input,textarea,select,button,
    table,th,td,ul, li {margin:0;padding:0;border:0;font-size:16px; font-family: 'Noto Sans KR', sans-serif;color:#333;font-weight:normal;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0; box-sizing: border-box;}
    header, footer, section, article, aside, nav, details, menu, figure, figcaption {display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
    
    a:link , a:visited {text-decoration:none;}
    a:hover,a:focus {text-decoration:none;}
    *{-webkit-text-size-adjust:none;}
    
    input,textarea,select,button{font-size:16px;font-family:'Noto Sans KR', sans-serif;}
    img,fieldset {border:0;}
    form,fieldset,input {margin:0;padding:0;}
    em,address,optgroup {font-style:normal;font-weight:normal;}
    button {border:none 0;margin:0;padding:0;overflow:visible;cursor:pointer;background:none;}
    
    
    ol,ul,li {list-style:none;}
    table {border-spacing:0;border-collapse:collapse;}
    hr {display:none;}
    legend {position:absolute;top:-1000px;left:-1000px;visibility:hidden;}
    caption {height:0;line-height:0;font-size:0px;visibility:hidden;}
    
    .skipNavi {position:absolute;left:0;top:0;z-index:999;width:100%;text-align:center;}
    .skipNavi a {position:absolute;top:-999px;left:-999px;}
    .skipNavi a:focus, .skipNavi a:active, .skipNavi a:hover {display:block;top:0;left:0;padding:7px 10px 5px;background:#000;color:#fff;font-weight:bold;font-size:16px;text-decoration:none;}
    
    input[placeholder] { color:#999;}
    ::-webkit-input-placeholder { /* WebKit browsers */ color:#999;}
    :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ color:#999;}
    ::-moz-placeholder {/* Mozilla Firefox 19+*/ color:#999;}
    :-ms-input-placeholder {/* ie10+*/ color:#999;}
    
    input {color:#333 !important;}
    
    select {
        cursor:pointer;
    }
    
    
    p,a,span, select, input {word-break:break-all;}
    summary {display:none;}
    @media screen and (max-width:500px){
        a, p, span, button {font-size:14px;}
    }
    .wrap-mobile {width:800px; margin:100px auto; padding:40px; max-width:100%; background-color:#fafafa;}
    .wrap-mobile .container {background-color:#fff;}
    .header {padding:20px; background-color:#1C3351; text-align: center;}
    .header .logo {font-size:24px; color:#fff; text-align: center; font-weight:600;}
    .content {padding:40px;}
    .content .title.type01 {margin-bottom:20px; font-size:18px; font-weight:500; text-align: center;}
    .content .btn.type01 {display:inline-block; max-width:200px; margin:0 auto; margin-top:20px; padding:10px 20px; color:#fff; background-color:#1C3351; text-align: center;}
    .footer {padding:40px; text-align: center;}
    .footer p {font-size:14px; color:#999;}
    .body.type01 {margin-bottom:10px;}

    @ layout.blade.php

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
    <div class="wrap-mobile">
        <div class="container">
            {{ $header ?? '' }}
    
            <div class="content">
                {{ $slot }}
            </div>
    
            {{ $footer ?? '' }}
        </div>
    </div>
    </body>
    </html>

    @ message.blade.php(여기의 $slot부분이 우리가 만든 메일 view 내용이 들어갈 부분)

    @component('mail::layout')
        {{-- Header --}}
    
        @slot('header')
            @component('mail::header', ['url' => config('app.url')])
                {{ config('app.name') }}
            @endcomponent
        @endslot
    
       {{-- Body --}}
        {{ $slot }}
    
        {{-- Footer --}}
        @slot('footer')
            @component('mail::footer')
                © {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.')
            @endcomponent
        @endslot
    @endcomponent

    @ header.blade.php

    <header class="header">
        <a href="{{ config("app.url") }}">
            <!-- <img src="/img/logo.png" alt=""> -->
            {{config("app.name")}}
        </a>
    </header>

    @ footer.blade.php

    <footer class="footer">
        {{ Illuminate\Mail\Markdown::parse($slot) }}
    </footer>

     

    @ views/passwordResets/created.blade.php(이 부분이 message.blade.php의 slot로 들어가는거임)

    @component('mail::message')
        <div id="resetPassword">
            <h3 class="title type01">비밀번호 초기화</h3>
    
            <p class="body type01">안녕하세요, {{$receiver ? $receiver->email : ""}}님,</p>
    
            <p class="body type01">
                {{config("app.name")}} 서비스 계정의 비밀번호를 초기화하시려면 비밀번호 초기화 버튼을 눌러주시기 바랍니다.
            </p>
    
            <div class="btns" style="text-align:center;">
                <a href="{{$passwordReset ? $passwordReset->resetUrl() : ''}}" class="btn type01 width-100 bg-primary">비밀번호 초기화</a>
            </div>
        </div>
    @endcomponent

     

    # 메일 보내기

    @ PasswordResetController.php

    <?php
    
    
    namespace ShinHyungJune\SocialLogin\Http;
    
    use App\Mail\PasswordResetCreated;
    use App\Models\PasswordReset;
    use App\Models\User;
    use Carbon\Carbon;
    use Illuminate\Http\Request;
    use Illuminate\Routing\Controller;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\DB;
    use Illuminate\Support\Facades\Hash;
    use Illuminate\Support\Facades\Mail;
    use Illuminate\Support\Facades\Password;
    use Illuminate\Support\Facades\Redirect;
    use Inertia\Inertia;
    use Laravel\Socialite\Facades\Socialite;
    
    class PasswordResetController extends Controller
    {
        public function create()
        {
            return Inertia::render("PasswordResets/Create");
        }
    
        public function store(Request $request)
        {
            $request->validate([
                "email" => "required|email|string|max:500"
            ]);
    
            $message = "";
    
            if(!User::where("email", $request->email)->exists()) {
                $message = __("socialLogin.passwordReset.send_fail");
    
                return Inertia::render("PasswordResets/Create", ["message" => $message]);
            }
    
            $token = random_int(100000000,999999999);
    
            $passwordReset = PasswordReset::where("email", $request->email)->first();
    
            $passwordReset ? $passwordReset->update([
                "email" => $request->email,
                "token" => $token
            ]) : $passwordReset = PasswordReset::create([
                "email" => $request->email,
                "token" => $token
            ]);
    
            Mail::to($request->email)->send(new PasswordResetCreated(User::where("email", $request->email)->first(), $passwordReset));
    
            $message = __("socialLogin.passwordReset.send_success");
    
            return Inertia::render("PasswordResets/Create", ["message" => $message]);
        }
    
        public function edit(Request $request)
        {
            return Inertia::render("PasswordResets/Edit", [
                "email" => $request->email,
                "token" => $request->token
            ]);
        }
        
        public function update(Request $request)
        {
            $request->validate([
                "email" => "required|email|max:500",
                "token" => "required|string|max:5000",
                "password" => "required|string|min:8|max:500|confirmed"
            ]);
    
    
            $passwordReset = PasswordReset::where("email", $request->email)
                ->where("token", $request->token)
                ->first();
    
            $user = User::where("email", $request->email)->first();
    
            $message = __("socialLogin.passwordReset.reset_fail");
    
            if($user && $passwordReset){
                $user->update(["password" => Hash::make($request->password)]);
    
                $message = __("socialLogin.passwordReset.reset_success");
            }
    
            return Inertia::render("PasswordResets/Edit", ["message" => $message]);
        }
    }

     

    # 메일 미리 보기

    @ web.php

    <?php
    
    use Illuminate\Support\Facades\Route;
    
    /*
    |--------------------------------------------------------------------------
    | Web Routes
    |--------------------------------------------------------------------------
    |
    | Here is where you can register web routes for your application. These
    | routes are loaded by the RouteServiceProvider within a group which
    | contains the "web" middleware group. Now create something great!
    |
    */
    
    
    Route::get("/mailable", function(){
       return (new \App\Mail\PasswordResetCreated(new \App\User(), new \App\PasswordReset()));
    });

     

    LIST

    'Laravel' 카테고리의 다른 글

    Test(테스트, TDD)  (0) 2021.02.05
    인스타그램 API 연동  (2) 2021.02.05
    whereExists  (0) 2020.08.18
    Object array 유효성 검사하는법  (0) 2020.07.19
    Job(Queue)  (0) 2020.06.14

    댓글

Designed by Tistory.