2

Can someone please provide the correct method to send an email verification upon user creation? This is the important part...

a) I would like the user to have immediate access upon signing up. But if the user has not yet clicked clicked on the verification link within 48 hours, I would like to deny them logging in until they have clicked on the link.

My code so far sends an email verification but the user has continuos access to the application with or without clicking on the verification link (so my code is of course incomplete).

client.js

Template.join.events({
'submit #join-form': function(e,t){
 e.preventDefault();
  var firstName=  t.find('#join-firstName').value,
  lastName=  t.find('#join-lastName').value,
  email = t.find('#join-email').value,
  password = t.find('#join-password').value,
  username = firstName.substring(0) + '.' + lastName.substring(0),
  profile = {
    fullname: firstName + ' ' + lastName
  };
  Accounts.createUser({
    email: email,
    username: username,
    password: password,
    userType: // 'reader' or 'publisher'
    createdAt: new Date(),
    profile: profile
 }, function(error) {
if (error) {
  alert(error);
} else {
  Router.go('home');
       }
    });
   }
});

server.js

Meteor.startup(function () {
process.env.MAIL_URL = 'smtp://postmaster.....';
Accounts.emailTemplates.from = "no-reply@mydomain.com";
Accounts.emailTemplates.sitename = "My SIte Name";

Accounts.emailTemplates.verifyEmail.subject = function(user) {
  return 'Please confirm tour Email address' ;
},
Accounts.emailTemplates.verifyEmail.text = function(user, url) {
  return 'Click on the link below to verify your address: ' + url;
}
Accounts.config({
  sendVerificationEmail: true
});

My attempt have been made through own readings on meteor docs and looking at other code on SO. I am stuck guys. Thanks for the support.

meteorBuzz
  • 3,110
  • 5
  • 33
  • 60

1 Answers1

3

I think the basic idea is to have some validation code eg in Accounts.validateLoginAttempt which you want to check every time before user logs in. What you can do is to store the date&time when user signs up in user.profile.joinDate. If a user tries to login

  • Check if the email address has been verified or
  • check if the user is logging within the grace period of 48 hrs
isWithinGracePeriod = function(user) { 
      ** TBD returning true or false. 
         This can be tricky when you 
         have multiple instances in 
         different time-zones. 
      ** }

and

Accounts.validateLoginAttempt(function(attempt){
  if (attempt.user && attempt.user.emails && !attempt.user.emails[0].verified ) {
    console.log('No verification action received yet.');
    return isWithinGracePeriod(attempt.user); 
  }
  return true;
});

Further, here is the HTML/spacebars stuff:

<body>
    {{ > start }}
</body>

<template name="start">
  {{#if currentUser}}{{>showUserProfile}}{{else}}{{> login}}{{/if}}
</template>

<template name="login">
   ## Grab username/password here
</template>

If the login template is created, we can try to capture the verification code after the user clicked the verification link. Note that, if no user is logged in, then login will be rendered, so we attach to login via

Template.login.created = function() {
  if (Accounts._verifyEmailToken) {
    Accounts.verifyEmail(Accounts._verifyEmailToken, function(err) {
      if (err != null) {
        if (err.message = 'Verify email link expired [403]') {
          var message ='Sorry this verification link has expired.';
          console.log(message);    
          alertBox = Blaze.renderWithData(Template.Alert, {message: message}, $("body").get(0));
        }
      } else {
        var message = "Thank you! Your email address has been confirmed.";
        console.log(message);
        alertBox = Blaze.renderWithData(Template.Alert, {message: message}, $("body").get(0));
      }
    });
  }
};

The verification link is send in "hook" to Accounts.createUser:

Accounts.onCreateUser(function(options, user) {
   user.profile = {};
   Meteor.setTimeout(function() {
   Accounts.sendVerificationEmail(user._id);
     }, 2 * 3000);
  return user;
});
Steffo
  • 622
  • 5
  • 6
  • To be fair the 48 hour grace period need not be so strict. As long as there is validation with the users email address at some point. I saw that with Accounts.validateLoginAttempt there is an 'allowed' callback function that returns either true or false. To begin with, can you show me how to set LoginWithEmail. I do not understand what it currently does when the user clicks on the link. +1 for the methodical approach towards the question, thank you Steffo – meteorBuzz Dec 02 '14 at 17:12
  • Re-edited the answer. When the user clicks the verification link (which looks this http://localhost:3000/#/verify-email/lots-of-funny-chars), the `login` template is created and `Accounts.verifyEmail` grabs the funny-chars and verifies them (Meteor takes care about this). – Steffo Dec 02 '14 at 18:54
  • Thanks for the input. I will apply this code and let you know how I get on soon and vote accordingly. – meteorBuzz Dec 03 '14 at 09:54
  • This has been helpful. I am still trying to deconstruct what is going on. What I would like todo is go back and simplify. Can you show me a clean way to send an email verification link to the user. That is all please? – meteorBuzz Dec 05 '14 at 12:29