How to resend verification email?

It often happens that someone registers an account with us but doesn’t confirm the registration via email - either because they didn’t receive the email, it ended up in their spam folder, or they simply forgot to do so. This leads to a situation where the user can’t register a new account (the email address is already taken) and the registration email can’t be found.

When I look at the callback account->onVerifyEmail(), it requires the user to be logged in. But this is a deadlock for me: the user can’t log in because they haven’t confirmed their email, and they can’t confirm their email because they haven’t logged in.

Is there a solution to resend the registration email to a specified address?

Assuming you’re on RainLab.User v3…

You only get stuck like this when Require Activation is on (User Settings, Sign In tab). With it off, people can sign in before verifying, and you remind them on the account page. That’s what we do on our site (we also limit what they can do until they are activated)

{% if user and not user.hasVerifiedEmail %}
    <div class="alert alert-warning">
        <p>Your email address has not been verified. Check your inbox for the link.</p>
        <button type="button" data-request="account::onVerifyEmail" data-request-flash>
            Send the verification email again
        </button>
    </div>
{% endif %}

Keep Send Activation Email (Notifications tab) on so the first email still goes out when they register.

If you need Require Activation on, there are two ways out:

1. Forgot password works as a resend. Completing a password reset marks the email as verified, because the person has just proved they own the inbox. You could add a line to the “check your email” message: “Didn’t get it? Reset your password to confirm your address.”

2. A resend form that takes an email address. onVerifyEmail needs a signed-in user, but the model method behind it doesn’t, so a page handler can call it:

function onResendVerification()
{
    $email = trim((string) post('email'));

    $limiter = new \System\Classes\RateLimiter('resend-verify:'.strtolower($email));
    if ($limiter->tooManyAttempts(1)) {
        throw new ApplicationException('Please wait a minute and try again.');
    }
    $limiter->increment();

    $user = \RainLab\User\Models\User::where('email', $email)->first();
    if ($user && !$user->hasVerifiedEmail()) {
        $user->sendEmailVerificationNotification();
    }

    Flash::success('If that address belongs to an unconfirmed account, we have sent a new link.');
}
<form data-request="onResendVerification" data-request-flash>
    <input type="email" name="email" required>
    <button type="submit">Resend confirmation email</button>
</form>

It shows the same message whether or not the address has an account, so the form can’t be used to look up who’s registered. The rate limit stops it being used to flood someone’s inbox.

Thank you for the detailed analysis. I see that there are options; I just need to choose the one that works best for me—that’s up to me.