I am trying to use SendGrid Mail service to send mail and it throw error 400 in the nodejs server.
Is this from Sendgrid or frontend?
I also got the content in the quill rich text editor, because I'm using it.
Every time I get "BAD REQUEST" in the server, but it's sent like [object null reference].
Mail.js, where I'm creating the function:
// SendGrid
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
// cb means callback for error or success
const sendEmail = (email, subject, content, cb) => {
const msg = {
from: email,
to: 'oabdulazeez70#gmail.com',
cc: 'letayoknow#gmail.com',
subject: subject,
text: content,
// html: content,
};
sgMail
.send(msg)
.then(() => {
console.log('Email sent');
// console.log(cb(null, data));
})
.catch((error) => {
console.error(error);
// console.log(cb(error, null));
});
};
module.exports = sendEmail;
index.js //server (backend)
const express = require('express');
const bodyParser = require('body-parser');
const exphbs = require('express-handlebars');
const cors = require('cors');
const path = require('path');
const dotenv = require('dotenv');
const app = express();
dotenv.config({ path: './config/config.env' });
// bring in SendEmail
const sendMail = require('./mail');
// View engine setup
app.engine('handlebars', exphbs({ defaultLayout: false }));
app.set('view engine', 'handlebars');
// Static folder
app.use('/public', express.static(path.join(__dirname, 'public')));
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cors());
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'contact.html'));
// res.sendFile('contact.html', { root: '.' });
});
//old key
//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
app.post('/send', (req, res) => {
const { subject, to, content, email } = sendMail;
sendMail(email, to, subject, content, () => {
if (err) {
console.error(err.ResponseError);
res.status(400).json({ message: 'Internal Error' });
} else if (res.status(500)) {
console.log('Error Something happned!');
} else {
console.log(data);
res.json({ message: 'Message Sent' });
}
});
console.log(req.body);
});
// Setting PORT from .env
const PORT = process.env.PORT || 5000;
// console.log(process.env);
app.listen(PORT, () => console.log(`Server Started on ${PORT}`));
app.js (frontend)
const getIds = (id) => {
return document.getElementById(id);
};
const form = document.querySelector('#form');
form.addEventListener('submit', (e) => {
e.preventDefault();
const from = getIds('from').value;
const subject = getIds('subject').value;
const emailFormat = quill.root.innerHTML;
const content = (getIds('content').value = emailFormat);
const data = {
from,
subject,
content,
};
axios
.post('/send', data, {
headers: {
'Content-Type': 'application/json',
},
})
.then((res) => {
form.reset();
quill.setContents([{ insert: '\n' }]);
M.toast({ html: 'Email Sent!!' });
console.log(res);
})
.catch((err) => console.log(err));
});
You can use #sendgrid/mail NPM module.
import sgMail from '#sendgrid/mail';
const setApiKey = () => sgMail.setApiKey(process.env.SENDGRID_API_KEY);
export const sendEmail = ({
emailTo, data, emailFrom
}) => {
return new Promise(async (resolve, reject) => {
try {
setApiKey();
const msg = {
to: [emailTo],
from: emailFrom, // Use the email address or domain you verified above
subject: 'Sending with Twilio SendGrid is Fun',
html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
const result = await sgMail.send(msg);
resolve(result);
} catch (_e) {
console.log('Error in sendEmail: ', _e.response.body);
reject(_e.response.body);
}
});
};
For your case use this one
import sgMail from '#sendgrid/mail';
const setApiKey = () => sgMail.setApiKey(process.env.SENDGRID_API_KEY);
export const sendEmail = (email, subject, content) => {
return new Promise(async (resolve, reject) => {
try {
setApiKey();
const msg = {
from: email,
to: 'oabdulazeez70#gmail.com',
cc: 'letayoknow#gmail.com',
subject: subject,
text: content,
};
const result = await sgMail.send(msg);
resolve(result);
} catch (_e) {
console.log('Error in sendEmail: ', _e.response.body);
reject(_e.response.body);
}
});
};
app.post('/send', (req, res) => {
try {
const { email, subject, content } = req.body;
await sendMail(email, subject, content);
res.json({ message: 'Message Sent' });
} catch (error) {
res.status(400).json({ message: 'Something went wrong' });
}
console.log(req.body);
});
Related
I am currently learning how to use the fetch api for my front-end. I continue to get the XHR 404 POST error.
//Backend file
const express = require("express");
const app = express();
require("dotenv");
const Port = process.env.PORT || 5000;
app.use(express.static("public"));
app.use(express.json());
app.use(
express.urlencoded({
extended: false,
})
);
const nodemailer = require("nodemailer");
const Mail = require("nodemailer/lib/mailer");
require("nodemailer-mailgun-transport");
app.use(express.json());
app.get("/", (req, res) => {
res.sendFile("/public");
res.sendFile("/public/js/mail.js");
});
app.listen(Port, (req, res) => {
console.log(`listening on port ${Port}`);
});
app.post("/email"),
(req, res) => {
FromMailjs = req.body;
console.log(FromMailjs);
const transporter = nodemailer.createTransport({
auth: {
user: process.env.Email,
pass: process.env.Pass,
},
});
const MailOptions = {
from: req.body.Email,
to: process.env.MyEmail,
text: `${req.body.FirstName}, ${req.body.LastName}
, ${req.body.PhoneNumber}, ${req.body.Email}`,
};
transporter.sendMail(MailOptions, (error, info) => {
if (error) {
console.log(error);
res.send("error");
} else {
console.log("Email sent");
res.send("success");
}
});
};
//Frontend file
const ContactForm = document.querySelector(".contact-form");
ContactForm.addEventListener("submit", (e) => {
e.preventDefault();
let FirstName = document.getElementById("Fname");
let LastName = document.getElementById("Lname");
let PhoneNumber = document.getElementById("PhoneNumber");
let Email = document.getElementById("Email");
const FormData = {
FirstName: FirstName.value,
LastName: LastName.value,
PhoneNumber: PhoneNumber.value,
Email: Email.value,
};
const PostOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(FormData),
};
console.log(FormData);
fetch("/email", PostOptions);
});
XHRPOSThttp://localhost:5000/email
[HTTP/1.1 404 Not Found 27ms]
I have tried changing the routes hoping that it was just a routing issue and I still get the same error. I was using XHR before fetch and I got the same 404 error. My front-end is receiving the correct information but I can't get my backend to receive the information.
You have a typo. Please use:
app.post("/email", (req, res) => {
Instead of:
app.post("/email"),
(req, res) => {
I have added a model to my frontend and backend so that users can update their profile (name age etc.), however, when I'm trying to update my test user name it's not updating, and I'm recieving the below error message in my terminalTerminal error
See below my server.js and profile.js
SERVER.JS
const express = require("express");
const bodyParser = require("body-parser");
const bcrypt = require("bcrypt-nodejs");
const cors = require("cors");
const knex = require("knex");
const register = require("./controllers/register");
const signin = require("./controllers/signin");
const profile = require("./controllers/profile");
const image = require("./controllers/image");
const { Pool } = require("pg");
const morgan = require("morgan");
const nodemailer = require("nodemailer");
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "1";
const pool = new Pool({
connection: process.env.POSTGRES_URI,
ssl: process.env.DATABASE_URI ? true : false,
});
const db = knex({
client: "pg",
connection: process.env.POSTGRES_URI,
ssl: {
rejectUnauthorized: false,
},
});
const app = express();
app.use(bodyParser.json());
app.use(morgan("combined"));
app.use(cors());
app.get("/", (req, res) => {
res.send("it is working");
});
app.post("/signin", (req, res) => {
signin.handleSignin(req, res, db, bcrypt);
});
app.post("/register", (req, res) => {
register.handleRegister(req, res, db, bcrypt);
});
app.get("/profile/:id", (req, res) => {
profile.handleProfile(req, res, db);
});
app.post("/profile/:id", (req, res) => {
profile.handleProfileUpdate(req, res, db);
});
app.put("/image", (req, res) => {
image.handleImage(req, res, db);
});
app.post("/imageurl", (req, res) => {
image.handleApiCall(req, res);
});
app.post("/sendResetPassowrdLink", (req, res) => {
const email = req.body.email;
pool.query(`SELECT * FROM login WHERE email='${email}'`).then((data) => {
if (data.rowCount === 0) {
return res
.status(401)
.json({ message: "user with that email does not exists" });
}
const { email } = data.rows[0];
const emailBody = `your sever url is http://localhost:3001/resetpassword/${btoa(
email
)}`;
res.send(emailBody);
});
});
app.get("/resetpassword/:token", (req, res) => {
const email = atob(req.params.token);
const { newPassowrd, newPassowrdConfirm } = req.body;
if (newPassowrd !== newPassowrdConfirm) {
return res.status(400).json({ message: "passowrd does not match" });
}
const hash = bcrypt.hashSync(newPassowrd);
pool
.query(`UPDATE login SET hash='${hash}' WHERE email='${email}'`)
.then((data) => {
if (data.rowCount === 1) {
return res
.status(200)
.json({ message: "password updated successfully" });
}
});
});
const PORT = process.env.PORT || 3005;
app.listen(PORT, () => {
console.log(`app is running on port ${PORT}`);
});
PROFILE.JS
const handleProfile = (req, res, db) => {
const { id } = req.params;
db.select("*")
.from("users")
.where({ id })
.then((user) => {
if (user.length) {
res.json(user[0]);
} else {
res.status(400).json("not found");
}
})
.catch((err) => res.status(400).json("error getting user"));
};
const handleProfileUpdate = (req, res, db) => {
const { id } = req.params;
const { name, age, pet } = req.body.formInput;
db("users")
.where({ id })
.update({ name })
.then((resp) => {
if (resp) {
res.json("success");
} else {
res.status(400).json("Unable to udpate");
}
})
.catch((err) => console.log(err));
};
module.exports = {
handleProfile,
handleProfileUpdate,
};
I also recently added docker container to my backend and database, could that be the cause for the issue?
below is my github backend repo with the docker included
https://github.com/Moshe844/smartbrain-api/tree/master
I am trying to add a contact form that will send to a dedicated gmail account. I have got the contact form working independently but when I try and add it to my working project it does not work and the error I get is:
Cannot POST /api/send
The project is a MERN stack. Below is the mailer.js middleware:
import nodemailer from 'nodemailer'
import config from '../config'
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587,
auth: {
user: process.env.username,
pass: process.env.password,
}
});
const send = ({ email, name, text }) => {
const from = name && email ? `${name} <${email}>` : `${name || email}`
const message = {
from,
to: 'react.nodemailer#gmail.com',
subject: `New message from ${from} at creating-contact-forms-with-nodemailer-and-react`,
text,
replyTo: from
};
return new Promise((resolve, reject) => {
transporter.sendMail(message, (error, info) =>
error ? reject(error) : resolve(info)
)
})
}
export default send
The server.js on the backend is:
const express = require('express');
const connectDB = require('./config/db');
const path = require('path');
// // ********************
// // CONTACT FORM
// // ********************
const cors = require ("cors")
const nodemailer = require("nodemailer")
// // ********************
// // CONTACT FORM
// // ********************
const app = express();
// // Connect Database
connectDB();
// Init Middleware
app.use(express.json());
// // ********************
// // CONTACT FORM
// // ********************
app.use(cors());
app.post('/contact', (req, res) => {
const { email = '', name = '', message = '' } = req.body
mailer({ email, name, text: message }).then(() => {
console.log(`Sent the message "${message}" from <${name}> ${email}.`);
res.redirect('/#success');
}).catch((error) => {
console.log(`Failed to send the message "${message}" from <${name}> ${email} with the error ${error && error.message}`);
res.redirect('/#error');
})
})
// // ********************
// // CONTACT FORM
// // ********************
// Define Routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));
app.use('/api/send', require('./routes/api/send'));
// Serve static assets in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
The contact form is:
import React, { Component } from "react";
import axios from "axios";
class ContactForm extends Component {
constructor() {
super();
this.state = {
name: "",
email: "",
message: "",
status: "Submit"
};
}
handleSubmit(event) {
event.preventDefault();
this.setState({ status: "Sending" });
axios({
method: "POST",
url: "api/send",
data: this.state,
}).then((response) => {
if (response.data.status === "sent") {
alert("Message Sent");
this.setState({ name: "", email: "", message: "", status: "Submit" });
} else if (response.data.status === "failed") {
alert("Message Failed");
}
});
}
handleChange(event) {
const field = event.target.id;
if (field === "name") {
this.setState({ name: event.target.value });
} else if (field === "email") {
this.setState({ email: event.target.value });
} else if (field === "message") {
this.setState({ message: event.target.value });
}
}
This is the api POST route.
var express = require('express');
var config = require('config');
var router = express.Router();
var cors = require('cors');
// #route POST api/send
// #desc Send email on contact page
// #access Public
router.post('/api/send',(req, res, next ) => {
var name = req.body.name
var email = req.body.email
var subject = req.body.subject
var message = req.body.message
var content = `
name: ${name} \n
email: ${email} \n
subject: ${subject} \n
message: ${message} `
var post = {
from: name,
subject: subject,
text: content
}
});
module.exports = router;
I have been trying to debug this for a week or so. I am currently trying to find out why the POST route is not working.
The error codes I have got are 500 internal server error and 404 not found. The url it will be going to is http://localhost:5000/api/send
Change
router.post('/api/send',(req, res, next )
to
router.post('/',(req, res, next )
In your express app your already have.
app.use('/api/send', require('./routes/api/send'));
Thus, for all "/api/send" we will look in the file './routes/api/send'.
The way you defined it you will have to query it like http://localhost:5000/api/send/api/send.
You will have
router.post('/',(req, res, next ) => {
var name = req.body.name
var email = req.body.email
var subject = req.body.subject
var message = req.body.message
var content = `
name: ${name} \n
email: ${email} \n
subject: ${subject} \n
message: ${message} `
var post = {
from: name,
subject: subject,
text: content
}
});
module.exports = router;
Also how about moving routes to its own file. i.e in server have
app.use(require('./routes/api'));
And in ./routes/api/index.js have the definitions there. i.e
const express = require('express');
const router = express.Router();
router.use('/api/send', require('./send'));
module.exports = router;
You can directly register the route on the express app like below,
app.post('/api/send',function(){
//..send code
//nodemailer.send("blabla")
});
instead of registering routes both on app and router.
I'm using the MERN stack to build an application for the first time.
In order to log HTTP requests I use "morgan".
I managed to send data to mongodb which seems to be working fine. The problem is that my post request is not coming through. It says "pending" for 4 minutes, then fails.
Here's what I think is the relevant part of my code:
"server.js":
const express = require("express");
const mongoose = require("mongoose");
const morgan = require("morgan");
const path = require("path");
const cors = require("cors");
const app = express();
const PORT = process.env.PORT || 8080;
const routes = require("./routes/api");
const MONGODB_URI =
"...";
mongoose.connect(MONGODB_URI || "mongodb://localhost/app", {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.connection.on("connected", () => {
console.log("Mongoose is connected.");
});
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());
app.use(morgan("tiny"));
app.use("/api", routes);
app.listen(PORT, console.log(`Server is starting at ${PORT}`));
Then I've put my routes into another file "api.js":
const express = require("express");
const router = express.Router();
const Lane = require("../models/lanes");
router.get("/", (req, res) => {
Lane.find({})
.then(data => {
res.json(data);
console.log("Get request successful!");
})
.catch(error => {
console.log("Error: ", error);
});
});
router.post("/save", (req, res) => {
const data = req.body;
const newLane = new Lane();
newLane.collection.insertMany(data, err => {
if (err) {
console.log(err);
} else {
console.log("Multiple docs inserted");
}
});
});
module.exports = router;
I'm using axios to send the request. This happens after submitting a form within my application.
reducer function:
const reducer = (state, action) => {
switch (action.type) {
case "add":
axios({
url: "http://localhost:8080/api/save",
method: "POST",
data: [...state, { id: uuid(), title: action.title, tasks: [] }]
})
.then(() => {
console.log("Data has been sent to the server");
})
.catch(() => {
console.log("Internal server error");
});
return [...state, { id: uuid(), title: action.title, tasks: [] }];
The reducer is being used by my context provider component, which looks like this:
export function LanesProvider(props) {
const [lanes, dispatch] = useReducer(reducer, defaultLanes);
return (
<LanesContext.Provider value={lanes}>
<DispatchContext.Provider value={dispatch}>
{props.children}
</DispatchContext.Provider>
</LanesContext.Provider>
);
}
The "add" method inside my reducer is being called when submitting a form inside another component.
Please let me know if I can add anything to my question that would help.
Thank you in advance!
you are not sending any response back to client. Try to modify post method like
router.post("/save", (req, res) => {
const data = req.body;
const newLane = new Lane();
newLane.collection.insertMany(data, err => {
if (err) {
console.log(err);
res.send(err)
} else {
console.log("Multiple docs inserted");
res.send("Multiple docs inserted")
}
});
});
I'm not sure why it's saying the object is empty. This is my testing block of code.
describe("POST /users", () => {
let body = {
name: "testing",
email: "testing#testing.com",
password: 123456
};
it("Creates a new user", done => {
request(app)
.post("/register")
.send(body)
.end((err, res) => {
if (err) return done(err);
expect(res.body).to.be.equal("testing");
done();
});
});
});
Is there something I'm missing for the test to recognize the information being passed in? As in the payload since I thought that is what .send(payload) was for.
Thanks for the clarity.
** Update Controller and more information **
// Testing
let request = require("supertest");
let expect = require("chai").expect;
let app = require("../../server/server");
describe("GET /test", function() {
it("Returns a json for testing", done => {
request(app)
.get("/test")
.end((err, res) => {
done();
});
});
});
describe("POST /users", () => {
let body = {
name: "testing",
email: "testing#testing.com",
password: 123456
};
it("Creates a new user", done => {
request(app)
.post("/register")
.send(body)
.expect(res => {
expect(res.body).to.be.equal("testing");
})
.end(done);
});
});
// User routes
const express = require("express");
const router = express.Router();
// Load User Model
const User = require("../../models/User");
// #route GET api/users/test
// #desc Tests user route
// #access Public
router.get("/test", (req, res) => res.json({ msg: "Users Works" }));
router.post("/register", (req, res) => {
User.findOne({ email: req.body.email }).then(user => {
if (user) {
res.status(409).json({ msg: "User exist" });
} else {
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
});
newUser
.save()
.then(user => res.status(200).send(user))
.catch(err => console.log(err));
}
});
});
module.exports = router;
// Server
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
const users = require("./routes/api/users");
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// DB Config
const db = require("../config/keys").mongoURI;
// Connect to MongoDB Atlas
mongoose.connect(
db,
{ useNewUrlParser: true },
(err, client) => {
if (err) {
console.log("Error occurred while connecting to MongoDB Atlas...\n", err);
}
console.log("Connected...");
}
);
// Routes
app.use("/api/users", users);
const port = process.env.PORT || 5000;
let server = app.listen(port, () =>
console.log(`Server running on port ${port}`)
);
module.exports = server;