skip to Main Content

Introduction

My POST request works offline i.e. on localhost, but doesn’t work when the website is deployed.

I am using nextjs, node, nodemailer, axios and nginx. I have also used fetch instead of axios and it gave me the same issue.

The situation

I have a handleSubmit function, that takes some inputs from a contact form and sends it to my Gmail account:

        axios({
            method: "POST",
            url: "/api/submit",
            data: body,
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            }
        }).then((response) => {
            if (response.data.status === 'success') {
                alert("Email sent, awesome!");
            } else {
                alert("Oops, something went wrong. Try again")
            }
        })

The api/submit.js is as follows:

import nodemailer from "nodemailer"

var transport = {
    service: 'gmail',
    host: "smtp.gmail.com",
    port: 587,
    secure: false,
    auth: {
        user: process.env.USER,
        pass: process.env.PASS
    }
}

var transporter = nodemailer.createTransport(transport);

transporter.verify((error, success) => {
    if (error) {
        console.log("There was an error:" + error);
    } else {
        console.log("Server is ready to take messages")
    }
})

export default async (req, res) => {
    switch (req.method) {
        case "POST":
            var name = req.body.name;
            var content = name " text "
            var mail = {
                from: name,
                to: "[email protected]",
                text: content
            }
    
            transporter.sendMail(mail, (err, data) => {
                if (!err) {
                    res.json({
                        status: "success"
                    })
                    res.end();
                }
            })
            break
        case "GET":
            res.status(200).json({name:"John Doe"})
            break
        default:
            res.status(405).end()
            break
    }

}

The code works locally when I run npm run dev, or npm start it posts to http://localhost:3000/api/submit and I receive the email within seconds.

However, when I deploy the website on DigitalOcean and hit the submit button nothing happens for 60 seconds then I get a status code of 504 on my POST request. If I send a GET request to api/submit, it works and I see the JSON for that request, so it’s an issue with the POST request specifically.

My Nginx logs it as the following:

2021/02/27 13:59:35 [error] 95396#95396: *3368 upstream timed out (110: Connection timed out) while reading response header from upstream, client: my.ip, server: website.com, request: "POST /api/submit HTTP/1.1", upstream: "http://127.0.0.1:3000/api/submit", host: "website.com", referrer: "https://website.com/contact"

I’ve been trying to debug it for days now, but I just can’t figure it out.
Anyone have any ideas?

EDIT 01.03.2021 The problem is resolved embarrassingly.

Turns out the ports were all open, telnet worked for all mail ports and smtp hosts.

When I hard coded the username/password e.g. for ephemeral mail user: "[email protected]", pass: "fakepassword"; the email would send in production.

Turns out my process.env.USER and process.env.PASS were not being replaced with the values of process.env.USER/PASS in .env during npm run build, because I was cloning my GitHub repo, which didn’t contain my .env file. After creating my .env file on the server and running npm run build the code worked fine.

Thank you for the replies, sorry for the hassle.

4

Answers


  1. Chosen as BEST ANSWER

    I suspect I'm not the first to do this but it's rather embarrassing.

    First, I confirmed that the ports were all open, telnet worked for all mail ports and smtp hosts.

    Then, when I hard coded the username/password e.g. for ephemeral mail user: "[email protected]", pass: "fakepassword"; the email would send in production.

    Then I realized that my process.env.USER and process.env.PASS variables were not being replaced with the true values of process.env.USER/PASS in .env during npm run build, because I was cloning my GitHub repo, which didn't contain my .env file. Meaning I was trying to login as username = "process.env.USER" and password = "process.env.PASS".

    After creating my .env file on the server and running npm run build the code worked fine.

    Thank you for the replies and sorry for the hassle.


  2. I guess that is not a problem with your code, but with the deploy process. Are you requesting to yor API adress directly or passing to a proxy? If you’re using a proxy, maybe the proxy was not redirecting to your application in a right way

    Login or Signup to reply.
  3. I think, it works for you in your local machine, as the localhost is there. But in the server, maybe, it’s not the same.

    You can check your hostnames in the server by the following command

    cat /etc/hosts
    

    If the host name is different, possibly you have the allow the CORS as well. A good place to check is in your browser inspect (in google chrome, right-click -> Inspect)

    Then check if you find any message related the access to the server from your frontend.

    Login or Signup to reply.
  4. Kindly check that from Digital Ocean where your application is deployed, port is opened or not for following host.
    Host:smtp.gmail.com Port: 587

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search