So many websites uses registration by email. Email registration is easy and economical also than registration with mobile phones. Now we will see how to do this stuff with Java, jQuery and MySQL.

Things which I have used

  1. JDK 8
  2. Tomcat 8
  3. JQuery 
  4. Bootstrap for jQuery
  5. MySql
  6. Eclipse

Project

I have created this project for explaining Login, Email Registration, Change Password, Forgot Password functionalities. You need to download the project for better understanding

Project set-up

This is simple eclipse project, You can import as existing eclipse project. It needs email server to send registration emails to users. So you have to set-up your own email server

Open Setup.java and update below fields
  public static final String DB_URL = "jdbc:mysql://localhost:3306/demos";
  public static final String DB_USERNAME = "root";
  public static final String DB_PASSWORD = "your root user password";
  public static final String MAIL_USERNAME = "mail id here"; // like example@outlook.com
  public static final String MAIL_PASSWORD = "password here";  // your mail password here
  public static final String MAIL_SMTP_HOST = "smtp password here"; // smtp.live.com
  public static final String MAIL_REGISTRATION_SITE_LINK = "http://localhost:8080/demos/VerifyRegisteredEmailHash";

Setup Loggers

Go to WEB-INF folder. Open log4j.properties file. Give logs file path at below line
log4j.appender.Appender2.File=/var/lib/logs/demos.log

Lets build database

Here creating one table is enough. Find below for table create statement
CREATE TABLE `demo_user` (
  `user_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `email` varchar(100) NOT NULL,
  `first_name` varchar(20) NOT NULL,
  `last_name` varchar(20) NOT NULL,
  `email_verification_hash` varchar(45) DEFAULT NULL,
  `email_verification_attempts` int(11) DEFAULT NULL,
  `status` varchar(15) DEFAULT 'new',
  `created_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `password` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `email_UNIQUE` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='User Table';

Flow of the program

  1. User Enter Required details ( Email, Password...etc )
  2. Create User Account, keep status as "new", create Account activation hash code
  3. Send Account Activation Link with hash code to Registered Email
  4. User will click on activation link. Now hash code will be submitted to server
  5. Get the hash code from database. Check this hash code with User registered hash code
  6. If hash code matches, Update User Account status as "active" , else Increment verification attempts by 1 
  7. If verification attempts reaches 20, then regenerate verification code and resend activation link to user registered email

Database Queries

Find below for database queries which are useful for Email registration

// To know whether email already registered or not
select * from DEMO_USER where EMAIL = ?

// To create new account
insert into DEMO_USER (EMAIL,FIRST_NAME,LAST_NAME,EMAIL_VERIFICATION_HASH,PASSWORD) values (?,?,?,?,?)

// To verify Email verification hash code
select * from DEMO_USER where USER_ID = ? and EMAIL_VERIFICATION_HASH = ?

// To update user account status
update DEMO_USER set STATUS = ? where USER_ID = ?

// To update email verification attempts
update DEMO_USER set EMAIL_VERIFICATION_ATTEMPTS = EMAIL_VERIFICATION_ATTEMPTS + 1 where USER_ID = ?

// To select email verification attempts
SELECT EMAIL_VERIFICATION_ATTEMPTS from DEMO_USER

// To update email verification hash
update DEMO_USER set EMAIL_VERIFICATION_HASH = ?, EMAIL_VERIFICATION_ATTEMPTS = ? where USER_ID = ?

Front end

I built HTML pages with jQuery, Bootstrap, Validator.js. Its hard to explain everything here, so please download the project. Basic input fields looks like below code. Here we are taking 4 input values from users
<form class="form-horizontal" id="formRegister" data-toggle="validator" role="form">
  <div class="form-group">
    <label for="inputEmail" class="control-label">Email</label>
    <input name="inputEmail" pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$" class="form-control" id="inputEmail" placeholder="Enter Email" data-error="Enter valid Email" required>
    <div class="help-block with-errors"></div>
  </div>
  <div class="form-group">
    <label for="inputFirstName" class="control-label">First Name</label>
    <input pattern="[A-Za-z0-9]{1,20}" name="inputFirstName" class="form-control" id="inputFirstName" placeholder="Enter First Name" data-error="First name should not be null. It should be less than 20 characters. Use only A-Z, a-z, 0-9 charecters" required>
    <div class="help-block with-errors"></div>
  </div>
  <div class="form-group">
    <label for="inputLastName" class="control-label">Last Name</label>
    <input pattern="[A-Za-z0-9]{1,20}" name="inputLastName" class="form-control" id="inputLastName" placeholder="Enter Last Name" data-error="last name should not be null. It should be less than 20 characters. Use only A-Z, a-z, 0-9 charecters" data-toggle="tooltip" data-placement="right" required>
    <div class="help-block with-errors"></div>
  </div>
  <div class="form-group">
    <label for="inputPassword" class="control-label">Password</label>
    <input type="password" pattern="[A-Za-z0-9@#$%!^&*]{6,30}" name="inputPassword" class="form-control" id="inputPassword" placeholder="Enter Password" data-error="Password should not be null. It should be greater than 6 and less than 30 characters . Use only A-Z, a-z, 0-9, @ # $ % ! ^ & * charecters" required>
    <div class="help-block with-errors"></div>
  </div>
  <div class="form-group">
    <label for="inputPassword1" class="control-label">Confirm Password</label>
    <input type="password" name="inputPassword1" class="form-control" id="inputPassword1" data-match="#inputPassword" placeholder="Enter Password Again" data-error="It should not be null and should match with above password" required>
    <div class="help-block with-errors"></div>
  </div>
  <div class="form-group">
      <button style="width:100%" type="submit" class="btn btn-default btn-primary">Register</button>
  </div>
</form>

RegisterEmail.java

This servlet is responsible is for taking inputs from user and creating account for users and sending verification emails
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.mail.MessagingException;
import com.sl.dao.UserDAO;
import com.sl.db.DBException;
import com.sl.model.StatusPojo;
import com.sl.model.UserPojo;
import com.sl.util.BCrypt;
import com.sl.util.GlobalConstants;
import com.sl.util.MailUtil;
import com.sl.util.Utils;

/**
 * Servlet implementation class RegisterEmail
 */
@WebServlet("/RegisterEmail")
public class RegisterEmail extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public RegisterEmail() {
        super();
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // collect all input values
        String email = request.getParameter("inputEmail");
        String firstName = request.getParameter("inputFirstName");
        String lastName = request.getParameter("inputLastName");
        String password = request.getParameter("inputPassword");
        UserPojo up = new UserPojo();
        up.setEMAIL(email);
        up.setFIRST_NAME(firstName);
        up.setLAST_NAME(lastName);
        
        // generate hash for password
        up.setPASSWORD(BCrypt.hashpw(password,GlobalConstants.SALT));
        
        // generate hash code for email verification
        String hash = Utils.prepareRandomString(30);
        
        // generate hash for password
        up.setEMAIL_VERIFICATION_HASH(BCrypt.hashpw(hash, GlobalConstants.SALT));
        StatusPojo sp = new StatusPojo(); 
        String output = "";
        try {
            
            // check whether email exists or not
            if(!UserDAO.isEmailExists(email)) {
                // create account if email not exists
                String id = UserDAO.insertRow(up);
                // send verification email
                MailUtil.sendEmailRegistrationLink(id, email, hash);
                sp.setCode(0);
                sp.setMessage("Registation Link Was Sent To Your Mail Successfully. Please Verify Your Email");
                output = Utils.toJson(sp);
            } else {
                // tell user that the email already in use
                sp.setCode(-1);
                sp.setMessage("This Email was already registered");
                output = Utils.toJson(sp);
            }
            
        } catch (DBException|MessagingException e) {
            e.printStackTrace();
            sp.setCode(-1);
            sp.setMessage(e.getMessage());
            output = Utils.toJson(sp);
        }   
        // send output to user
        PrintWriter pw = response.getWriter();
        pw.write(output);
        pw.flush();
        pw.close();
    }       
}

MailUtil.java

    public static void sendEmailRegistrationLink(String id, String email, String hash) throws AddressException, MessagingException {
        Properties props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", Setup.MAIL_SMTP_HOST);
        props.put("mail.smtp.port", "587");

        Session session = Session.getInstance(props,
          new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(Setup.MAIL_USERNAME, Setup.MAIL_PASSWORD);
            }
          });

        String link = Setup.MAIL_REGISTRATION_SITE_LINK+"?scope=activation&userId="+id+"&hash="+hash;
        
          StringBuilder bodyText = new StringBuilder(); 
            bodyText.append("<div>")
                 .append("  Dear User<br/><br/>")
                 .append("  Thank you for registration. Your mail ("+email+") is under verification<br/>")
                 .append("  Please click <a href=\""+link+"\">here</a> or open below link in browser<br/>")
                 .append("  <a href=\""+link+"\">"+link+"</a>")
                 .append("  <br/><br/>")
                 .append("  Thanks,<br/>")
                 .append("  SodhanaLibrary Team")
                 .append("</div>");
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(Setup.MAIL_USERNAME));
            message.setRecipients(Message.RecipientType.TO,
                InternetAddress.parse(email));
            message.setSubject("Email Registration");
            message.setContent(bodyText.toString(), "text/html; charset=utf-8");
            Transport.send(message);
    }
In this file, you can find code for sending email verification to user

VerifyRegisteredEmailHash.java

This servlet is responsible for verifying email, activating user accounts
import java.io.IOException;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sl.dao.UserDAO;
import com.sl.db.DBException;
import com.sl.model.UserPojo;
import com.sl.util.BCrypt;
import com.sl.util.GlobalConstants;
import com.sl.util.MailUtil;
import com.sl.util.Utils;

/**
 * Servlet implementation class VerifyRegisteredEmailHash
 */
@WebServlet("/VerifyRegisteredEmailHash")
public class VerifyRegisteredEmailHash extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public VerifyRegisteredEmailHash() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // get user Id and email verification code Hash code  
        String userId = request.getParameter("userId");
        String hash = BCrypt.hashpw(request.getParameter("hash"), GlobalConstants.SALT);
        String scope = request.getParameter("scope");
        String message = null;
        try {
            // verify with database
            if(UserDAO.verifyEmailHash(userId, hash) && scope.equals(GlobalConstants.ACTIVATION)) {
               //update status as active
               UserDAO.updateStaus(userId, "active");
               message = "Email verified successfully. Account was activated. Clic <a href=\"login.html\">here</a> to login";
            } else {
               //now increment verification attempts 
               int attempts = UserDAO.incrementVerificationAttempts(userId);
               if(attempts == 20) {
                   // reset verification code if attempts equal to 20 
                   String hashcode = Utils.prepareRandomString(30);
                   UserDAO.updateEmailVerificationHash(userId, BCrypt.hashpw(hashcode, GlobalConstants.SALT));
                   UserPojo up = UserDAO.selectUSER(userId);
                   MailUtil.sendEmailRegistrationLink(userId, up.getEMAIL(), hashcode);
                   message = "20 times Wrong Email Validation Input Given. So we are sent new activation link to your Email";
               } else {
                   message = "Wrong Email Validation Input";   
               }
            }
        } catch (DBException e) {
            e.printStackTrace();
            message = e.getMessage();
        } catch (AddressException e) {
            message = e.getMessage();
            e.printStackTrace();
        } catch (MessagingException e) {
            message = e.getMessage();
            e.printStackTrace();
        }
        if(message!=null) {
            request.setAttribute(GlobalConstants.MESSAGE, message);
            request.getRequestDispatcher("/messageToUser.jsp").forward(request, response);  
        } 
    }
}

11 comments:

  1. Hi Thanks for the tutorial its awesome But i am getting error of communication failure Whats wrong

    ReplyDelete
    Replies
    1. i am using outlook mail to send registration mails here, some times its blocking mails from programme

      Delete
  2. hi srinivas
    Same issues of communication failure to me also ,I downloaded projects and copied files to my current projects in eclipse .but when running the project and while doing registration its showing me database exception failure ....I am using same outlook email of mine help me .
    however I scrolled your blog and its wonderful....

    ReplyDelete
    Replies
    1. add e.printStackTrace() to catch blocks of UserDAO.java, trace the exception and share the same

      Delete
  3. This will be the Error Occuring For Me please give me a Solution For this Problem


    Error: 534-5.7.9 Application-specific password required. Learn more at 534 5.7.9 https://support.google.com/accounts/answer/185833 x67sm87045386pff.47 - gsmtp

    ReplyDelete
  4. we probably trying to send mail through a gmail account in which you've enabled 2-factor authentication. A 6-digit authentication token we have to create through which account or gmail id we are going to use that mail application . Google Authenticator app is required to proceed.we have to create for our gmail account . Alternatively, we can generate app-specific passwords through Google's web based ui and use that user name and the generated password to our web application.

    ReplyDelete
  5. Error :

    DEBUG 2016-10-10 15:13:07,926 [http-nio-1515-exec-27] com.sl.emailRegistration.RegisterEmail - 534-5.7.14 Please log in via your web browser and
    534-5.7.14 then try again.
    534-5.7.14 Learn more at
    534 5.7.14 https://support.google.com/mail/answer/78754 yi2sm2779237pab.17 - gsmtp

    ReplyDelete
  6. DEBUG 2017-03-30 13:41:14,396 [http-bio-8080-exec-12] com.sl.dao.UserDAO - Data truncation: Data too long for column 'email_verification_hash' at row 1
    DEBUG 2017-03-30 13:41:14,400 [http-bio-8080-exec-12] com.sl.emailRegistration.RegisterEmail - Excepion while accessing database

    ReplyDelete
  7. i am getting
    DEBUG 2017-10-03 18:55:40,689 [http-nio-8081-exec-1]Could not connect to SMTP host: smtp.XXXXX.com, port: 587

    ReplyDelete

Blogroll

Follow this blog by Email

Popular Posts