• Emails In Your React App Made Easy with Nodemailer
  • Originally written by Paige Niedringhaus
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: fireairforce
  • Proofreader: Portandbridge

Resetting passwords in JavaScript applications is not that complicated

Password reset in MERN applications

I overestimated how hard it would be to do that before I actually tried to build an emailing password reset for my MERN application. As far as I know, sending email in a JavaScript application is difficult, but I still want to try.

For months, I’ve been slowly building this application and adding it to a user registration service in order to hone my JavaScript full stack skills.

First, I used React as the front end, Express/Node.js back end and docker-driven MySQL database to build the application. I use docker-comemess.yml to launch the entire application with one command (check out this blog post if you want to read more about my development with Docker).

After I started building the application, I used Passport. Js and JSON Web Tokens (JWTs) to add permissions to the application. If you’re interested in this, you can read this article to see what makes nue play xīn. I spent a lot of time — I ran into a lot of obstacles that held me back a lot. But determination and I can’t solve a problem once it takes root in my mind, I try to figure it out and move on.

When I decided to fix the problem of sending password reset links via email (just as with real websites, users, myself included, would inevitably forget their passwords), I felt even more miserable. Although practically every website has this feature, it’s not that easy to do. But I was wrong, and I’m glad I was.

Nodemailer — The Magic Bullet

When I started searching around for a solution to my password reset feature, I found a number of articles recommending Nodemail.

When I visited its website, the first thing I read was:

Nodemailer is a module of Node.js that makes it easy to send email. The project began in 2010 when there was no better solution for sending email messages, and today it is the default solution chosen by most Node.js users. – Nodemailer

You know what? This is no joke. It’s not difficult to send an email.

Of course I did more research to make sure I felt more confident about the technology before I started, and what I saw on NPM and Github reassured me.

Nodemailer are:

  • NPM is downloaded more than 615,000 times a week,
  • Over 10,000 stars on Github,
  • So far there are 206 versions,
  • Over 2,500 dependency packages,
  • It has existed in some form or fashion since 2010.

Well, that seems like something WORTH interviewing for in my own project.

Implementing Nodemailer (front-end and back-end) in code

My password reset feature doesn’t require a lot of bells and whistles, just:

  • A way to send an email to a user’s address,
  • The email contains a link that redirects to protected pages on my site where the user resets their password,
  • They can then log in using the new password,
  • I also want the password reset link to expire after a period of time for better security.

Here’s what I did.

Front-end code (client folder) – Sends reset messages

I started with the React code first, because I had to have a page where users could enter their email address and use the email containing the reset link.

ForgotPassword.js

Ok, I know this is a big screenshot, but I’ll break it down (I used Polacode in VS Code to make this beautiful screenshot, fYI). If you want to copy/paste the actual code, go to the repository.

What you should really care about is the component’s sendEmail and Render methods. The rest of the code just sets the initial state and variables, and the styles of the buttons and elements.

Rendering methods

Notice inside the Render method that I have a simple input box for the user to enter his E-mail address, and pressing the submit button triggers the this.sendemail () method. In addition, I build in some error and success handling if the user does not enter the email, or if the server replies that the email was successfully sent or it is not a recognized address.

Send email function

All HTTP requests are done using Axios, which makes it very easy for the server to make AJAX calls, even simpler than the built-in Web API Fetch (), in my opinion.

When users enter their E-mail, they make a POST request to the server and wait for the server to respond. If I can’t find the email address, I can tell the user I typed it in the wrong way. Or if the user is not registered, they can go to a registration page and create a new account; If the email address matches the address in our database, they will receive a message indicating that the password reset link has been successfully sent to their email address.

Let’s now turn to the back-end code

Backend code (API folder) – Send reset mail

forgotPassword.js

The back-end code is much more involved. This is where Nodemailer comes in.

The first thing the Sequelize method does when the email address entered by the user enters the forgotPassword route is check to see if the email exists in my database. If the user does not receive a notification, they may have typed a mistake, and if so, a series of other events will be initiated.

Only connecting them all together was a little difficult at first.

Step 1: Generate the token

Once you confirm that the E-mail has been associated with a user in the database, the first step is to generate a token that can be associated with the user’s account and set the duration of the token.

Node.js has a built-in module called Crypto, which provides encryption, which is an advanced way of saying that I can use crypto.randomBytes(20).tostring (‘hex’); This line of code simply generates a unique hash token. I then save this new token to the user’s configuration file in the database called resetPasswordToken. I also set a timestamp for the token’s expiration date. After sending the link, I made the link valid for 1 hour — date.now () + 36000.

Step 2: Create the Nodemailer transport

Next, I created an account where the Transporter method actually sends a password reset email link.

I chose to use Gmail because I personally use Gmail and I created a new virtual account to send emails. Since I don’t want to give away some credentials for this virtual account to anyone, I put them in a.env file that is included in.gitignore, so it will never be submitted to Github or anywhere else.

NPM package [dotenv] (https://www.npmjs.com/package/dotenv) is used to read the file and insert the email address and password to Nodemailer createTransport method.

Step 3: Create mail options

The third step is to create an email template, called mailOptions in Nodemailer, that users will see (this is where the verified email addresses they enter from the front end are used).

There are whole third-party libraries that can make nice emails using the Nodemailer module, but I just wanted a simple email, so I made this myself.

It contains the email address for sending (from) messages ([email protected], for me), the user’s email address in the to box, and the subject line is the line that holds the password reset link, And text is a simple string that contains some information and a resetting route to the site URL, including the token I created earlier, added at the end. This will allow me to verify that the user is who they say they are when they click on the link and go to the site to reset their password.

Step 4: Send an email

The last step in this file is actually to put together the code snippets I created earlier: transporter, mailOptions, and Token and use Nodemailer’s sendMail() function. If it works, I get a response with a return code of 200, and THEN I use that response to trigger a successful call to the client, and if something goes wrong, I log the error so I can see what went wrong.

Enable Gmail to send reset email

An additional pitfall to be aware of when setting up transport email, at least when using Gmail, is that all emails are sent from the transport.

In order to be able to send email from an account, two-step authentication must be disabled and the Allow Less Secure Apps setting must be turned on. See the screenshot below. To do this, enter the Settings center from here and open it.

Now, I can send reset emails without any problems. If you run into problems, check out Nodemailer’s FAQ for more help.

Front-end code — Update password screen

Great, now users should get a reset email in their mailbox, something like this.

If you’ve noticed, the third line is a link to my website (running locally on port 3031), another page called “reset”, followed by a hash token generated by the Node.js crypto module in the first step.

When users click this link, they are directed to a new page in the application called “Password Reset Screen,” which can only be accessed with valid tokens. If the token is expired or invalid, the user will see an error screen with a link to go home or try to send a new password reset email.

This is the React code that resets the screen.

ResetPassword.js

There are three main components to do the heavy lifting.

The initial component loads the lifecycle methods

This method is triggered as soon as you enter the page. It extracts the token from the URL query parameter and passes it to the server’s reset route to verify that the token is valid.

Then, if the server responds with “A-OK,” the token is valid and associated with the user, and if it responds with “no,” the token is invalidated for some reason.

Password Change function

This method is triggered if the user is authenticated and allows the password to be reset. It also accesses the specific route updatePasswordViaEmail on the server (I do this because I also provide another route for the user to change their password while logged in), and once the updated password is saved to the database, a successful response message is sent back to the client.

Rendering methods

The final part of this component is the Render method. Initially, a Loading message is displayed when the token is validated.

If the link is invalid in some way, an error message will be displayed on the screen, containing a link back to the home screen or the forgotten password page.

If the user has the right to reset the password, they have a new password input method called updatePassword(). Once the server responds with a successful password update, the update Boolean is set to true. Your password has been successfully reset… Message and login button.

Back-end code – reset and update passwords

Well, this project is in the final stages. These are the last two routes you need on the server side. These two methods correspond to the two methods I just did on the client side in the React resetpassword.js component.

resetPassword.js

This is the route to calling the lifecycle method on the componentDidMount client. It checks what is passed from the resetPasswordToken and date-time stamp of the linked query parameter to make sure everything is ok.

You’ll notice that the resetPasswordExpires parameter has the odd $gt: date.now () parameter. This is an operator alias comparator that Sequelize allows me to use, all $gt: Represents “priority over” regardless of who it is compared to, in which case it compares the current time to the expiration stamp saved to the database when the password reset email is sent to ensure that the password is reset less than an hour after the email is sent.

As long as both parameters are valid for the user, a successful response is sent to the client and the user can continue with the password reset.

updatePasswordViaEmail.js

This is the second route that is invoked when the user submits his password for update.

Once again, I found that the user in the database (username passes back to the client from the route on reset and remains in the application state until the update function is called), I use my bcrypt module to hash the new password (as my Passport. Js middleware does when I initially write the new user to the database), update the password for that user in the database with the new hash value, The resetPasswordToken and resetPasswordExpires columns are set to null, so the same link cannot be used more than once.

Once complete, the server returns a status code 200 response to the client with the success message “Password updated.”

You have successfully reset the user’s password via email. Is not difficult.

conclusion

At first glance, resetting a user’s password via an email link may seem daunting. But Nodemailer helped us simplify one major part (dealing with email). Once done, it’s just a few routes on the server side and entered on the client side in order to update the password for the user.

Check back in a few weeks and I’ll be writing about end-to-end testing with Puppeteer and Headeless Chrome or anything else related to Web development, so keep an eye on me in case you miss it.

Thanks for reading, I hope this gave you an idea of how to use Nodemailer to send password reset emails for MERN applications. Likes and shares would be greatly appreciated.

If you enjoyed reading this, you may also enjoy some of my other blogs:

  • The absolute easiest way to debug Node.js is to use VS Code
  • Implement JSON Web Tokens and Passport. Js in JavaScrip T applications using React
  • Sequelize: Like Mongoose but relative to SQL

Resources and more resources:

  • Nodemailer: nodemailer.com/about/
  • Nodemailer, making: github.com/nodemailer/…
  • Nodemailer, NPM: www.npmjs.com/package/nod…
  • MERN applications using Nodemailer Repo: github.com/paigen11/my…

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.