laravel邮箱验证不是「加个接口就自动生效」,必须同时满足三件事:user模型实现mustverifyemail、数据库有email_verified_at字段、路由显式启用auth::routes(['verify' => true]);漏掉任意一项,都会导致发不出邮件、跳转404或用户绕过验证。

直接说结论:Laravel邮箱验证不是「加个接口就自动生效」,必须同时满足三件事——User模型实现MustVerifyEmail、数据库有email_verified_at字段、路由显式启用Auth::routes(['verify' => true])。漏掉任意一项,都会导致发不出邮件、跳转404或用户绕过验证。
为什么 implements MustVerifyEmail 没反应?
只在User类里写implements MustVerifyEmail,什么都不会发生。Laravel 不会主动监听注册事件,也不会拦截未验证用户访问——它只是「声明能力」,不是「开启开关」。
- 检查
App\Providers\EventServiceProvider中是否注册了SendEmailVerificationNotification监听器;没用入门套件的话,手动注册注册逻辑后要补上:event(new Registered($user)) -
users表必须含email_verified_at字段(类型为TIMESTAMP NULL),否则调用$user->hasVerifiedEmail()会抛出Undefined property错误 - 字段存在但值为
NULL时,verified中间件才真正起效;设成非空时间戳=已验证,设为NULL=待验证
Auth::routes(['verify' => true]) 为什么必须显式调用?
这个调用是整个验证流程的「路由总开关」。不加它,/email/verify、/email/verify/{id}/{hash}、/email/resend三条路由根本不存在,点击邮件里的链接会直接 404。
- 它生成的验证 URL 含签名参数(
{id}和{hash}),由 Laravel 的signed中间件校验;自己拼接或删减会导致InvalidSignatureException - 命名路由
verification.notice必须存在,否则verified中间件重定向失败,报错Route [verification.notice] not defined - 别把
Auth::routes(['verify' => true])和Auth::routes()混用——后者不包含验证路由,前者覆盖并扩展它
verified 中间件为什么拦不住未验证用户?
verified中间件只检查email_verified_at IS NOT NULL,但它**不负责登录态**。如果只写->middleware('verified'),未登录用户访问也会被重定向到/email/verify,然后报错「Target class [App\Http\Controllers\Auth\VerificationController] does not exist」(Laravel 9+ 已移除该控制器)。
- 必须组合使用:
->middleware(['auth', 'verified'])——auth确保已登录,verified才检查邮箱状态 - 保护的是「登录后才能访问的页面」,比如
/dashboard、/profile;首页或登录页不该加verified - 如果用户已登录但未验证,
verified中间件会 302 重定向到命名路由verification.notice,所以你得提供auth.verify-email视图
邮件发不出或收不到的常见硬伤
验证流程卡在第一步,大概率是 SMTP 配置或环境没生效,而不是验证逻辑本身的问题。
-
.env里必须设MAIL_MAILER=smtp(旧版叫MAIL_DRIVER),且MAIL_FROM_ADDRESS不能为null,否则Mail::to()->send()直接报错 - QQ/163/Gmail 等邮箱必须用「授权码」而非账户密码,且对应 SMTP 服务需在邮箱后台手动开启(如 QQ 邮箱的「POP3/SMTP 服务」)
- 改完
.env后,务必运行php artisan config:clear;缓存不清理,配置永远不生效 - 开发时可临时切到
MAIL_MAILER=log,查看storage/logs/laravel.log里有没有Sending mail to记录,先确认逻辑走到发送环节
最易忽略的一点:验证链接的hash参数是基于当前域名 + 路由 + 用户 ID 动态签名的,换域名、改APP_URL、清缓存后没重跑config:clear,都可能导致签名失效——它不报错,只是静默拒绝,让人误以为是前端或路由问题。











