본문 바로가기

Dev/PHP

[PHP] Laravel - smtp를 이용한 메일 전송 구현

 

 

 

 

이번 포스팅에서는 Laravel 프레임워크에서 smtp를 사용해 웹페이지에서 메일을 보내는 기능을 구현해보겠습니다.

구현은 Gmail을 예시로 진행합니다.

 

1. Gmail IMAP 액세스 허용

구현에 앞서, Gmail 설정 페이지에서 IMAP 액세스를 허용해야 합니다.

아래의 링크로 Gmail 웹 페이지에 접근해주세요.

https://mail.google.com/mail/u/0/#inbox

 

Gmail

하나의 계정으로 모든 Google 서비스를 Gmail을 이용하려면 로그인하세요

accounts.google.com

 

 

로그인 후, 우측 상단 톱니바퀴 → 모든 설정 보기를 클릭합니다.

 

 

 

그럼 설정 페이지로 이동하게 되는데, 여기서 전달 및 POP/IMAP 항목을 클릭합니다.

 

 

IMAP 액세스 항목에서  "IMAP 사용"으로 상태를 변경하고 저장 버튼을 누릅니다.

 

2. Gmail App Password 설정

계정의 비밀번호로는 보안상의 문제로 웹 프로젝트에서 smtp를 통해 접속할 수가 없습니다.

이에 구글은 App Password라는 것을 제공해주는데, 이것을 통해 메일을 전달할 수 있습니다.

 

아래의 웹 페이지를 방문합니다.

https://myaccount.google.com/

 

Google 계정

Google 계정을 사용하면 데이터와 개인정보를 안전하게 보호할 수 있는 설정 및 도구에 빠르게 액세스할 수 있으며, 내 정보가 Google 서비스 맞춤설정에 사용되는 방법을 선택할 수 있습니다.

myaccount.google.com

 

 

좌측 메뉴에서 '보안'을 선택하고 'Google에 로그인' 항목에 앱 비밀번호를 클릭합니다.

 

앱 비밀번호를 클릭하면 비밀번호를 요구하는데, 로그인하고 진행하면 아래와 같은 화면이 나옵니다.

 

 

가장 아래 '앱 비밀번호를 생성할 앱 및 기기를 선택하세요.' 항목에서 다음과 같이 지정합니다.

 

 

기기 선택 항목은 아무거나 지정해도 무방합니다.

저는 기기 선택 이름을 Laravel로 지정했습니다.

 

 

생성 버튼을 누르면 기기용 앱 비밀번호를 발급해 줍니다.

 

이 비밀번호를 이용해 Gmail로 smtp를 이용할 수 있게 되었습니다.

이 앱 비밀번호는 Laravel 프로젝트의 .env 파일 설정에 필요하므로 어딘가 임시로 기록해 주세요.

 

 

위 표는 Gmail의 smtp / imap 서버 접속 정보입니다.

이 정보를 토대로 Laravel 프레임워크에서 메일 전송을 구현할 수 있습니다.

 

 

2. Laravel 프로젝트 .env 파일 세팅

.env 파일의 메일 설정 정보

Laravel 프로젝트로 돌아와 .env 파일을 열고 MAIL_ ~ 로 시작하는 설정 정보를 확인합니다.

위 사진의 항목들을 다음과 같이 변경해줍니다.

 

 

USERNAME은 Gmail의 계정 아이디를 입력하면 됩니다.

PASSWORD는 1번 항목에서 발급받은 App Password를 입력하면 됩니다.

 

3. route 정의

routes/web.php에 메일 전송을 위한 라우터들을 다음과 같이 정의해줍니다.

// 메일 전송을 위한 페이지로 이동한다.
Route::get('/mailSend', 'MailSendController@mailSend')->name('mailSend');

// 메일 전송 submit
Route::post('/mailSendSubmit', 'MailSendController@mailSendSubmit')->name('mailSendSubmit');

 

이제 web.php에서 정의한 라우트를 받아서 처리하는 컨트롤러를 작성합니다.

 

4. Controller 생성 및 view 요청 함수 정의

먼저 프로젝트 루트 경로로 이동한 다음, 아래의 명령어로 컨트롤러 스크립트를 생성합니다.

$ php artisan make:controller MailSendController

 

 

artisan 명령어로 생성한 컨트롤러 스크립트는 app/Http/Controllers 디렉터리에 생성됩니다.

MailSendController.php 파일에 먼저, 메일을 보내기 위한 함수를 작성합니다.

class MailSendController extends Controller
{
    public function mailSend(Request $request) {
    	return view('mailSend');
    }
}

mailSendSubmit 함수는 view를 작성한 뒤에 생성하겠습니다.

 

5. view 스크립트 작성

resources/views 경로에 mailSend.blade.php 라는 이름의 뷰 파일을 생성하고 아래의 내용을 작성합니다.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        
        <meta name="csrf-token" content="{{ csrf_token() }}">
        
        <!-- Ajax CDN -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        
        <title>Laravel Mail Send</title>
    </head>
    <body >
        <form onSubmit="return mailValidate(this)" >
            <h3>E - Mail Address</h3>
            <input type="email" name="emailAddr" id="emailAddr">
            <hr>
            <h3>Name</h3>
            <input type="text" name="name" id="name">
            <hr>
            <h3>Subject</h3>
            <input type="text" name="subject" id="subject">
            <hr>
            <h3>Content</h3>
            <textarea name="content" id="content"></textarea>
            <hr>
            <input type="submit" value="submit">
        </form>
    </body>

    <script>
        function mailValidate(e){
            var emailAddr = e.children.emailAddr.value.trim();
            var name = e.children.name.value.trim();
            var subject = e.children.subject.value.trim();
            var content = e.children.content.value.trim();

            if(emailAddr.length <= 0){
                alert('Please Enter Your Email');
                return false;
            }

            if(name.length <= 0){
                alert('Please Enter Your Name');
                return false;
            }

            if(subject.length <= 0){
                alert('Please Enter Subject');
                return false;
            }

            if(content.length <= 0){
                alert('Please Enter Content');
                return false;
            }

            $.ajax({
                headers: {
                    'X-CSRF-TOKEN' : $('meta[name="csrf-token"]').attr('content')
                },
                url: 'mailSendSubmit',
                type:'POST',
                data: {
                    'subject' : subject,
                    'content' : content,
                    'name' : name,
                    'emailAddr' : emailAddr
                },
                success: function(data){
                    e.children.emailAddr.value = '';
                    e.children.name.value ='';
                    e.children.subject.value ='';
                    e.children.content.value ='';
                    
                    alert('The mail has been sent successfully.');
                },,
                error: function(e){
                    console.log(e);
                    alert('The mail transfer failed.');
                }
            })
            return false;
        }
    </script>
</html>

 

submit요청은 본 예제에서는 ajax를 이용한 비동기 통신으로 전송합니다.

위 코드에서 중요한 부분은 이 부분입니다.

<meta name="csrf-token" content="{{ csrf_token() }}">

 

csrf-token은 Laravel 프로젝트에서 발급하는 요청 위조를 방지하기 위한 토큰입니다.

포스트 방식으로 데이터를 전송할 때 이 정보가 없으면 데이터를 보낼 수가 없습니다.

ajax에서 post 요청을 보낼 때 헤더 값에 넣어 줍니다.

 

이제 submit 요청을 받는 mailSendSubmit 컨트롤러 함수를 작성하겠습니다.

 

 

6. Controller에 post 요청 처리 함수 생성

3번 항목에서 미리 submitMailSend 요청 라우트를 정의했으므로 함수만 생성하면 됩니다.

...

use Illuminate\Support\Facades\Mail; // 추가

class MailSendController extends Controller
{
    public function mailSend(Request $request) {
        return view('mailSend;');
    }
    
    // == 추가 ==
    public finction mailSendSubmit(Request $request){
    	$data_arr = array(
            'subject' => $request->subject,
            'name' => $request->name,
            'emailAddr' => $request->emailAddr,
            'content' => $request->content
        );
        
        Mail::send('mail.mail_form', ['data_arr' => $data_arr], function($message) use ($data_arr){
            $message->to('email@example.com')->subject($data_arr['subject']);
            $message->from($data_arr['emailAddr']);
        });
        
        return $request;
    }
    
}

 

$request 객체를 통해 ajax에서 data라는 이름으로 보낸 값들을 읽어 들일 수 있습니다.

$message->to() 함수는 메일을 전송할 메일 주소를 의미하므로 예시에서 작성한 email@example.com 이 아닌 본래 주소를 정확하게 입력해야 합니다.

 

메일 전송에 사용되는 클래스는 다양하게 있습니다만, 본 예제에서는 메일 파사드를 이용해서 구현합니다.

파사드는 간결하고 보기 쉽게 코드를 작성할 수 있는 장점이 있습니다.

 

파사드에 대한 자세한 설명은 아래 링크를 참조해 주세요.

laravel.kr/docs/7.x/facades

 

라라벨 7.x - 파사드

라라벨 한글 메뉴얼 7.x - 파사드

laravel.kr

 

Mail 클래스의 send 함수의 첫 번째 인자인 'mail.mail_form'은 메일을 보낼 서식 파일명을 의미합니다.

즉, 받아온 정보를 mail.mail_form에 파싱 한 다음, 파싱 된 문서를 메일로 보내는 방식입니다.

그리고 send 함수의 두 번째 인자가 파싱 할 데이터를 의미합니다.

파싱이 완료가 되면 세 번째 인자인 callback 함수를 통해 $message라는 객체를 반환하게 되고, 이 $message 객체에 받는 사람과 보내는 사람을 지정하면 메일이 전송됩니다.

 

그리고 $request를 통해 ajax로 성공, 실패 여부와 상세 로그를 반환하게 됩니다.

 

7. mail.mail_form 생성

Mail:send 함수의 첫 번째 인자를 mail_mail_form으로 지정했는데, 이것은 resources/views/ 경로에 mail/mail_form.blade.php 파일을 의미합니다.

 

컨트롤러로 전달받은 데이터를 특정 양식으로 가공해서 메일을 전송해야 하는데, mail/mail.form.blade.php 파일이 그 양식이 됩니다.

 

 

resources/views 경로에 mail 디렉터리를 만들고 mail_form.blade.php 파일을 생성하고 아래의 내용을 작성합니다.

 

<table class="mail_form" border="0">
    <tr>
        <th>Subject</th>
        <td>{{ $data_arr['subject'] }}</td>
    </tr>
    <tr>
        <th>Name</th>
        <td>{{ $data_arr['name'] }}</td>
    </tr>
    <tr>
        <th>E-mail</th>
        <td>{{ $data_arr['emailAddr'] }}</td>
    </tr>
    <tr>
        <th>Content</th>
        <td><?php echo nl2br($data_arr['content']); ?></td>
    </tr>
</table>

 

content 값은 ml2br 함수를 적용해주지 않으면 내용이 줄 바꿈이 되지 않기 때문에 

 

<?php echo nl2br($data_arr['content']); ?>

 

이와 같은 형태로 지정해줍니다.

 

8. 내장 서버 실행

프로젝트 루트 경로로 돌아와 아래의 명령어를 실행하고 브라우저에서 /mailSend 페이지로 접속해봅니다.

$ php artisan serve

 

 

위와 같은 화면이 나온다면 정상적으로 라우트가 기능하고 있는 것입니다.

 

이제 적당히 내용을 채우고 submit 버튼을 클릭합니다.

 

 

위와 같은 알림 창이 메일이 정상적으로 전송되었음을 알려줍니다.

이제 Gmail로 접속해 정말로 메일이 도착했는지 확인해 봅니다.

 

 

 

메일이 정상적으로 전송되었음을 확인했습니다.

 

이것으로 Laravel 프레임워크에서의 smtp를 이용한 메일 전송을 구현해 보았습니다.