Skip to content

Instantly share code, notes, and snippets.

@EduardoSP6
Last active January 8, 2025 18:26
Show Gist options
  • Save EduardoSP6/dc4c233f5780f7f71e464b1d4675d205 to your computer and use it in GitHub Desktop.
Save EduardoSP6/dc4c233f5780f7f71e464b1d4675d205 to your computer and use it in GitHub Desktop.
Custom e-mail verification Laravel 7

Implementação de rotina de verificação da conta de e-mail

  • Criar migração do model User adicionando o campo:
$table->timestamp('email_verified_at')->nullable();
  • Implementar a interface MustVerifyEmail no model User;

  • O Laravel já possui um listener chamado SendEmailVerificationNotification que é responsavel por enviar o e-mail quando um usuario é registrado. Ele está relacionado ao evento Auth\Events\Registered. Então basta invocar o evento no método em que o usuário é cadastrado no sistema.

$user = User::create($data);

event(new Registered($user));

Os arquivos abaixos so existirão no projeto se você instalou o laravel/ui e gerou os arquivos via comando: php artisan ui [bootstrap, vue, react] --auth;

Auth\VerificationController possui a lógica de envio dos links e e-mail para verificação. Para registrar as rotas necessárias para o controller, passe a opção verify no metodo Auth::routes.

Auth::routes(['verify' => true]);

O middleware EnsureEmailIsVerified permite que somente os usuarios com email verificado acesse as rotas. Basta registrá-lo no Kernel e inserir nas rotas desejadas como 'verified';

A view de envio do e-mail para verificação está localizada em: resources/views/auth/verify.blade.php. Você pode alterá-la sem problemas. Se a view não estiver no projeto, verifique se você instalou o pacote laravel/ui. Você pode criar a view manualmente no mesmo diretório e com mesmo nome que irá funcionar;

O corpo do email é a classe VerifyEmail, que está associada a trait MustVerifyEmail, no método sendEmailVerificationNotification. Para customizar, basta sobrescrever o método no model User e criar sua própria classe de e-mail. Se for o caso, criar também um método para gerar a URL de ativação.

Exemplo:

Model User:

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Contracts\Auth\MustVerifyEmail;


class User extends Authenticatable implements MustVerifyEmail {
    
    public function sendEmailVerificationNotification()
    {
        try {
            // Backup your default mailer
            $backup = Mail::getSwiftMailer();

            // Setup your gmail mailer
            $host = env('MAIL_HOST');
            $port = env('MAIL_PORT');
            $encryption = env('MAIL_ENCRYPTION');
            $username = env('MAIL_USERNAME');
            $password = env('MAIL_PASSWORD');

            $transport = new Swift_SmtpTransport($host, $port, $encryption);
            $transport->setUsername($username);
            $transport->setPassword($password);

            $new_mail = new Swift_Mailer($transport);

            // Set the mailer as new_mail
            Mail::setSwiftMailer($new_mail);

            Mail::to($this->getEmailForVerification())
                ->send(new VerifyEmail($this));

            // Restore your original mailer
            Mail::setSwiftMailer($backup);

        } catch (\Exception $e) {
            \Log::error(get_class($this)."->sendEmailVerificationNotification() Error: "
                . $e->getMessage() ." - ". $e->getTraceAsString());
        }
    }

}

Classe VerifyEmail:

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;

class VerifyEmail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * @var User
     */
    private $user;

    public $verificationUrl;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        $this->verificationUrl = $this->verificationUrl();

        return $this
            ->from(env('MAIL_FROM_ADDRESS'), env('MAIL_FROM_NAME'))
            ->subject(\Lang::get('auth.verify_email_subject'))
            ->view('emails.verify_email');
    }

    /**
     * Get the verification URL
     *
     * @return string
     */
    private function verificationUrl()
    {
        return URL::temporarySignedRoute(
            'verification.verify',
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
            [
                'id' => $this->user->getKey(),
                'hash' => sha1($this->user->getEmailForVerification()),
            ]
        );
    }
}

Após implementado, os usuários existentes, após login, serão redirecionados para a view verify.blade.php. Então teremos que customizá-la para ativação da conta.

Obs.: Se o layout do e-mail possuir imagens como logo da empresa, etc. Utilizar o inline attachment juntamente com o asset helper do Laravel pois o provedor bloqueia imagens de URLs desconhecidas.

A solução foi inserir a linha no .env: ASSET_URL=${APP_URL} e inserir o codigo abaixo no arquivo blade do layout:

    @if(\Illuminate\Support\Str::contains(env('APP_URL'), 'https'))
        <img src="{{$message->embed(asset('images/logo.png'))}}" alt="logo">
    @else
        <img src="images/logo.png" alt="logo">
    @endif

Referência: https://laravel.com/docs/7.x/mail#inline-attachments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment