Send email with nodemailer - javascript

I save an email address in mysql bdd, and I would like to send an email to this address with nodemailer.
but I can't get the email in the back-end.
How can i get the email address from back-end please ?
I use apollo server for my back-end, and I use react-apollo for the frontend. I connect to my server with axios. But I can't find a way to retrieve the email address entered in the frontend.
My front-end code :
const CREATE_USER = gql`
mutation createUser($firstName: String!, $lastName: String!, $email: String!) {
createUser(firstName: $firstName, lastName: $lastName, email: $email) {
id
firstName
lastName
email
}
}
`;
class DataInput extends Component {
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
email: ''
}
}
handleSubmit(e){
e.preventDefault();
axios({
method: "POST",
url:"http://localhost:4000/graphql",
data: this.state
}).then((response)=>{
if (response.data.status === 'success'){
alert("Message Sent.");
this.resetForm()
}else if(response.data.status === 'fail'){
alert("Message failed to send.")
}
})
}
render() {
const { firstName, lastName, email } = this.state
return (
<div>
<div className="flex flex-column mt3">
<input
className="mb2"
value={firstName}
onChange={e => this.setState({ firstName: e.target.value })}
type="text"
placeholder="John"
/>
<input
className="mb2"
value={lastName}
onChange={e => this.setState({ lastName: e.target.value })}
type="text"
placeholder="Do"
/>
<input
className="mb2"
value={email}
onChange={e => this.setState({ email: e.target.value })}
type="text"
placeholder="your#email.com"
/>
</div>
<Mutation mutation={CREATE_USER} variables={{ firstName, lastName, email }}>
{ createUser => <button onClick={createUser}> Submit </button> }
</Mutation>
</div>
)
}
}
And my back-end function for send email :
const sendCertificate = () => {
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
transporter.verify((error, success) => {
if (error) {
console.log(error);
} else {
console.log('Server is ready to take messages');
}
});
transporter.sendMail(email, (err, data) => {
if (err) {
console.log(err)
}
else {
console.log('Success');
}
transporter.sendMail({
from: "sendcertificate#gmail.com",
to: email,
subject: "Submission was successful",
text: `Hello ${firstName} ${lastName}\n`
}, function(error, info){
if(error) {
console.log(error);
} else{
console.log('Message sent: ' + info.response);
}
});
}
)
}

Related

How to display server-side validation messages in the client side via react-query?

Here is the Express route for the signup API call, It works as expected on the server-side but I want to display these same validation messages in real-time when the user will put their credentials on the React client
app.post("/signup", async (req, res) => {
try {
// Validate data before submission
const { error } = registerValidation(
req.body.username,
req.body.firstname,
req.body.lastname,
req.body.email,
req.body.password
);
if (error) return res.status(400).send(error.details[0].message);
// Checking if username already exists
const usernameExist = await database.query(
"SELECT username FROM users WHERE username=$1",
[req.body.username]
);
if (usernameExist.rows[0])
return res.status(400).send("Username already taken!");
// Checking if email already exists
const emailExist = await database.query(
"SELECT email FROM users WHERE email=$1",
[req.body.email]
);
if (emailExist.rows[0])
return res.status(400).send("Email already exists!");
// Hash the password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt);
// Save the New User
const newUser = await database.query(
"INSERT INTO users(username, firstname, lastname, email, password) VALUES($1, $2, $3, $4, $5) RETURNING *",
[
req.body.username,
req.body.firstname,
req.body.lastname,
req.body.email,
hashedPassword,
]
);
res.json(newUser.rows[0]);
} catch (err) {
console.error(err.message);
}
});
And here is my fetch POST request for signup.
export const signUp = async (formData) => {
try {
const res = await fetch(`${API_URL}/signup`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),
});
if (!res.ok) {
const errMsg = await res.text();
throw new Error(errMsg);
}
await res.json();
} catch (err) {
console.error(err.message);
}
};
And here is the signup form using react-hook-form and react-query, the error message is displayed on the console but wanted to display it on screen in real-time while the user typing in the form without the need to submit the form to display those messages.
import React from "react";
import { useForm } from "react-hook-form";
import { joiResolver } from "#hookform/resolvers/joi";
import Joi from "joi";
import { useMutation } from "react-query";
import { useHistory } from "react-router-dom";
import { signUp } from "../API/API";
// Signup Form Validation
const schema = Joi.object({
username: Joi.string().min(3).required(),
firstname: Joi.string().min(3).required(),
lastname: Joi.string().min(3).required(),
email: Joi.string()
.min(6)
.required()
.email({ tlds: { allow: false } }),
password: Joi.string().min(6).required(),
});
const SignupForm = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({ resolver: joiResolver(schema) });
const mutation = useMutation(signUp);
const history = useHistory();
// To submit data on server
const onSubmit = async (data) => {
// const res = await mutation.mutate(data);
// console.log(res);
await mutation.mutate(data);
history.push("/");
};
console.log(errors);
return (
<div>
<h3>Sign up</h3>
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="text"
name="username"
placeholder="Username"
{...register("username", { required: true, min: 3 })}
/>
<p>{errors.username?.message}</p>
<br />
<input
type="text"
name="firstname"
placeholder="First Name"
{...register("firstname", { required: true, min: 3 })}
/>
<p>{errors.firstname?.message}</p>
<br />
<input
type="text"
name="lastname"
placeholder="Last Name"
{...register("lastname", { required: true, min: 3 })}
/>
<p>{errors.lastname?.message}</p>
<br />
<input
type="email"
name="email"
placeholder="Email"
{...register("email", {
required: true,
min: 6,
pattern: /^\S+#\S+$/i,
})}
/>
<p>{errors.email?.message}</p>
<br />
<input
type="password"
name="password"
placeholder="Password"
{...register("password", { required: true, min: 6 })}
/>
<p>{errors.password?.message}</p>
<br />
<button type="submit">Sign up</button>
</form>
</div>
);
};
export default SignupForm;
Please check with your syntax and all but did you check onError property?.
const { mutate } = useMutation(signUp, {
onSuccess: () => {
alert("successful");
},
onError: () => {
setStatus("there is an error");
},
});

How to send form as PDF attached to email (Nodemailer, React, Node.js)

There is a React form. What I want to achieve: I fill out the form. I click on the submit button. Then this form should generate a PDF that is sent as an attachment through Nodemailer. I already achieved sending the email and generating the PDF (can download it), but I do not know how to attach that PDF to the email. There is a signature too, that I could already attach to the PDF. I just want this PDF to be sent as an attachment in the email. Now when I submit, it just downloads the PDF for me (which is good) and only sends a simple email (no PDF attachment).
Server:
app.post('/create-pdf', (req, res) => {
pdf.create(pdfTemplate(req.body), {}).toFile('result.pdf', (err) => {
if (err) {
res.send(Promise.reject());
}
res.send(Promise.resolve());
});
});
app.post('/api/contact', contact);
app.get('/fetch-pdf', (req, res) => {
res.sendFile(`${__dirname}/result.pdf`);
});
Nodemailer:
exports.contact = async (req, res) => {
const htmlEmail = `
<h1>Hello!</h1>
`;
const mailOptions = {
from: req.body.name,
to: 'xxxxxxxxxxxxxxxxxxx',
subject: 'Message',
html: htmlEmail,
attachments: [{}],
};
const transporter = nodemailer.createTransport({
host: 'smtp.ethereal.email',
port: 587,
auth: {
user: 'xxxxxxxxxxxxxxx',
pass: 'xxxxxxxxxxxxxxx',
},
});
transporter.sendMail(mailOptions, (err, data) => {
if (err) {
res.json({
status: 'fail',
});
} else {
res.json({
status: 'success',
});
}
});
return console.log('email sent');
};
Client:
class Contact extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
phone: '',
message: '',
trimmedDataURL: null,
file: null,
};
}
sigPad = {};
clear = () => {
this.sigPad.clear();
};
trim = (e) => {
e.preventDefault();
this.setState({ trimmedDataURL: this.sigPad.getTrimmedCanvas().toDataURL('image/png') });
this.fileUpload(this.state.file).then((response) => {
console.log(response);
});
};
fileUpload(file) {
const url = 'http://localhost:3000/create-pdf';
const formData = new FormData();
formData.append('file', file);
const config = {
headers: {
'content-type': 'multipart/form-data',
},
};
return post(url, formData, config);
}
handleSubmit(e) {
e.preventDefault();
axios({
method: 'POST',
url: '/api/contact',
data: this.state,
}).then((response) => {
if (response.data.status === 'success') {
console.log('success');
} else if (response.data.status === 'fail') {
console.log('not success');
}
});
axios
.post('/create-pdf', this.state)
.then(() => axios.get('fetch-pdf', { responseType: 'blob' }))
.then((res) => {
const pdfBlob = new Blob([res.data], { type: 'application/pdf' });
saveAs(pdfBlob, 'newpdf.pdf');
});
}
render() {
return (
<div className="contact">
<h1>GET IN TOUCH</h1>
<div>
<form onSubmit={this.handleSubmit.bind(this)} method="POST">
<label htmlFor="name">NAME</label>
<br />
<input
onChange={this.onNameChange.bind(this)}
value={this.state.name}
type="text"
name="name"
placeholder="Your full name..."
/>
<br />
<label htmlFor="phone">PHONE</label>
<br />
<input
onChange={this.onPhoneChange.bind(this)}
type="text"
name="phone"
placeholder="Your phone number..."
value={this.state.phone}
/>
<br />
<label htmlFor="email">EMAIL</label>
<br />
<input
onChange={this.onEmailChange.bind(this)}
type="text"
name="email"
placeholder="Your email address..."
value={this.state.email}
/>
<br />
<label htmlFor="message">MESSAGE</label>
<br />
<textarea
onChange={this.onMessageChange.bind(this)}
type="text"
name="message"
value={this.state.message}
rows="5"
/>
<button className="contact-button" type="submit">
Send
</button>
<button onClick={this.createAndDownloadPdf}>download</button>
<br />
<SignatureCanvas
canvasProps={{ className: styles.sigPad }}
backgroundColor="gray"
ref={(ref) => {
this.sigPad = ref;
}}
/>
<img
alt=""
className={styles.sigImage}
src={this.state.trimmedDataURL}
style={{ width: '50px' }}
/>
<button className={styles.buttons} onClick={this.clear}>
Clear
</button>
<button
className={styles.buttons}
onClick={this.trim}
onChange={this.onFileChange.bind(this)}
>
Trim
</button>
</form>
</div>
</div>
);
}
onNameChange(event) {
this.setState({ name: event.target.value });
}
onEmailChange(event) {
this.setState({ email: event.target.value });
}
onPhoneChange(event) {
this.setState({ phone: event.target.value });
}
onMessageChange(event) {
this.setState({ message: event.target.value });
}
onFileChange(e) {
this.setState({ file: e.target.files[0] });
}
}
export default Contact;
attachments: [
{
filename: 'result.pdf',
path: '../grovespine/result.pdf',
},
],
a new result.pdf is always generated in my folder and just attach that to the nodemailer

User.id is undefined

I'm building a website where users can register, but when registration is complete nothing happens, its supposed to enter the site.
I have tested it with console.log and found out that my user.id is undefined.
this is my register on the server side:
const handleRegister = (req, res, db, bcrypt) => {
const { email, name, password } = req.body;
if (!email || !name || !password) {
return res.status(400).json('incorrect form submission');
}
const hash = bcrypt.hashSync(password);
db.transaction(trx => {
trx.insert({
hash: hash,
email: email
})
.into('login')
.returning('email')
.then(loginEmail => {
console.log(email)
return trx('users')
.returning('*')
.insert({
email: email,
name: name,
joined: new Date()
})
.then(user => {
res.json(user[0]);
})
})
.then(trx.commit)
.catch(trx.rollback)
})
.catch(err => res.status(400).json('unable to register ' + err))
}module.exports = {
handleRegister: handleRegister
};
and this is my register on the frontend:
import React from 'react';
class Register extends React.Component {
constructor(props){
super(props);
this.state = {
name: '',
email: '',
password: ''
}
}
onNameChange = (event) => {
this.setState({name: event.target.value})
}
onEmailChange = (event) => {
this.setState({email: event.target.value})
}
onPasswordChange = (event) => {
this.setState({password: event.target.value})
}
onSubmitSignIn = () => {
fetch('http://localhost:3000/register', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: this.state.name,
email: this.state.email,
password: this.state.password
})
})
.then(response => response.json())
.then(user => {
console.log(user.id);
if (user.id) {
console.log(user, user.id);
this.props.loadUser(user)
this.props.onRouteChange('home');
}console.log(user.id);
})
}
It is on the frontend I have set the console.log and it never enters the if statement.
How do I fix this?
If you are using mongodb the id field is defined as _id

Postman able to send POST request but not my frontend code

I've been trying to register a user through my vanilla JavaScript front-end, but have been unable to make a POST request that doesn't return a 400 status code. With Postman on the other hand, POST requests work just fine and the user is registered successfully.
This is what is logged when I make POST request:
HTML:
<body>
<form id="signup-form">
<h1>Sign up Form</h1>
<table>
<tr>
<td id="yo">User email: </td>
<td><input type="email" name="email" placeholder="email" /></td>
</tr>
<tr>
<td>Username: </td>
<td><input type="text" name="username" placeholder="username"/></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password" placeholder="password" /></td>
</tr>
<tr>
<td>Confirm Password:</td>
<td><input type="password" name="password2" placeholder="password" /></td>
</tr>
<tr>
<td><input type="submit" value="signup";/></td>
</tr>
</table>
</form>
<p>Already have an account? Login </p>
<script src="signup.js"></script>
</body>
This is where I need help as to why it returns a 400 response. Front-end JavaScript:
const form = document.getElementById('signup-form');
form.onsubmit = function(e) {
e.preventDefault();
const email = form.email.value;
const username = form.username.value;
const password = form.password.value;
const password2 = form.password2.value;
const user = {
email,
username,
password,
password2,
}
fetch('http://localhost:4002/api/user/register', {
method: 'POST',
body: JSON.stringify(user),
headers:{
'Content-Type': 'application/json'
}
}).then(res => {
console.log(res);
})
.catch(error => console.error('Error:', error));
form.reset();
}
Back-end code incase needed:
Route
//Register user
router.post('/register', (req, res, next) => {
const { errors, isValid } = validateRegisterInput(req.body);
//Check validation
if (!isValid) {
return res
.status(400)
.json(errors);
}
models.User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if (user) {
errors.email = 'Email already exists';
errors.username = 'Username already exists';
return res
.status(400)
.json(errors)
} else {
const data = {
email: req.body.email,
password: req.body.password,
username: req.body.username,
};
//Encrypting password
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(data.password, salt, (err, hash) => {
if (err)
throw err;
data.password = hash;
models.User.create(data).then(function(newUser, created) {
if (!newUser) {
return next(null, false);
}
if (newUser) {
return next(null, newUser);
}
})
.then( user => {
res.json(user)
})
.catch((err) => {
console.log(err);
})
})
})
}
})
});
Model
"use strict";
module.exports = function(sequelize, DataTypes){
var User = sequelize.define('User', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
username: {
type: DataTypes.STRING,
validate: {
len: [2, 20],
msg: 'Username must be between 2 and 20 characters'
}
},
email: DataTypes.STRING,
password: {
type: DataTypes.STRING,
validate: {
len: {
args: [5],
msg: 'Password must be atleast 5 characters'
}
}
}
});
User.associate = function(models) {
//associations can be defined here
}
return User;
};
Validation
const Validator = require('validator');
const isEmpty = require('./is-empty');
module.exports = function validatorRegisterInput(data) {
let errors = {};
data.username = !isEmpty(data.username)
? data.username
: '';
data.email = !isEmpty(data.email)
? data.email
: '';
data.password = !isEmpty(data.password)
? data.password
: '';
data.password2 = !isEmpty(data.password2)
? data.password2
: '';
if (Validator.isEmpty(data.email)) {
errors.email = 'Email field is required';
}
if (!Validator.isEmail(data.email)) {
errors.email = 'Email field is required';
}
if (Validator.isEmpty(data.password)) {
errors.password = 'Password is required';
}
if (!Validator.isLength(data.password, {
min: 5
})) {
errors.password = 'Password must be atleast 5 characters';
}
return {errors, isValid: isEmpty(errors)}
}
Please try changing the content type to application/json in your fetch call. A form submit would post the entire page back to the server in which case the content type you have would work but you are making a fetch call and preventing the default behavior.
fetch('http://localhost:4002/api/user/register', {
method: 'POST', // or 'PUT'
body: JSON.stringify(user), // data can be `string` or {object}!
headers:{
'Content-Type': 'application/json'
}
}).then(res => {
document.getElementById("yo").style.color = "red";
console.log(res);
})
.catch(error => console.error('Error:', error));

How to send form data from React to express

i'm fairly new in React. I'm trying to send register data to my backend from a from submit. I've tried the traditional method like setting post method and route in the form but that doesn't seem to work. Is there a way to send the data to back end then receive that data on the front end?
back end route: route is localhost:4000/api/users/register
router.post("/register", (req, res) => {
console.log(req.body)
console.log('Hit')
knex.select('*')
.from('users')
.where('email', req.body.email)
.then(function(results) {
knex('users')
.insert([{
first_name: req.body.first_name,
last_name: req.body.last_name,
phone: req.body.phone,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 15)
}])
.returning('id')
.then(function(id) {
req.session.user_id = id;
})
.catch(function(error) {
console.error(error)
});
}
})
.catch(function(error) {
console.error(error)
});
// }
});
React form code:
class Register extends Component {
constructor(props) {
super(props)
this.state = {
first_name: '',
last_name: '',
email: '',
password: '',
phone: ''
}
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit = (e) => {
e.preventDefault();
// get form data out of state
const { first_name, last_name, password, email, phone } = this.state;
fetch('http://localhost:4000/api/users/register' , {
method: "POST",
headers: {
'Content-type': 'application/json'
}
.then((result) => {
console.log(result)
})
})
}
render() {
const { classes } = this.props;
const { first_name, last_name, password, email, phone } = this.state;
return (
<div className="session">
<h1>Create your Account</h1>
<div className="register-form">
<form method='POST' action='http://localhost:4000/api/users/register'>
<TextField label="First Name" name="first_name" />
<br/>
<TextField label="Last Name" name="last_name" />
<br/>
<TextField label="Email" name="email" />
<br/>
<TextField label="Password" name="password" />
<br/>
<TextField label="Phone #" name="phone" />
<Button type='Submit' variant="contained" color="primary">
Register
</Button>
</form>
</div>
</div>
);
}
}
export default Register;
You have to send the data in your state to the server, and you have to use the json method on the response from fetch in order to access it.
fetch('http://localhost:4000/api/users/register', {
method: "POST",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(this.state)
})
.then((response) => response.json())
.then((result) => {
console.log(result)
})
You have not posted the data to the api. Also there are few coding errors. You need update code from
fetch('http://localhost:4000/api/users/register' , {
method: "POST",
headers: {
'Content-type': 'application/json'
}
.then((result) => {
console.log(result)
})
To
fetch('http://localhost:4000/api/users/register' , {
method: "POST",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(this.state)
})
.then((result) => result.json())
.then((info) => { console.log(info); })
Try using a cool library called axios. this would be the tone down explanation.
On the frontend, you would use axios to post data to your backend:
const reactData = [{ id: 1, name:' Tom'}, { id: 2, name:' Sarah'}];
const url = localhost:4000/api/users/register;
let sendData = () => {
axios.post(url, reactData)
.then(res => console.log('Data send'))
.catch(err => console.log(err.data))
}
On the backend side, you'll receive that data, simply by doing something like:
const url = localhost:4000/api/users/register;
const usersData= [];
let getData = () => {
axios.get(url)
.then(res => usersData.push(res.data))
.catch(err => console.log(err.data))
}

Categories

Resources