Email.js Works Locally, But not Once Deployed With React - javascript

I have set up Email.js to make a contact page for a website built with Next.js. It works completely fine when run locally, but does not work when hosted. The form does not even reset when the submit button is clicked. I do this in the sendEmail function. The error handler does not trigger either in the .then block. I get this error in the browser console:
Uncaught The user ID is required. Visit https://dashboard.emailjs.com/admin/integration
Here is how I send the emails:
export default function Book(props) {
const form = useRef();
const [sentMessage, setSentMessage] = useState();
const sendEmail = (e) => {
e.preventDefault();
emailjs
.sendForm(
props.SERVICE_ID,
props.EMAIL_TEMPLATE_ID,
form.current,
props.USER_ID
)
.then(
function (response) {
setSentMessage("Message sent successfully!");
},
function (error) {
setSentMessage("Message failed please email directly.");
}
);
document.getElementById("form").reset();
};
return (
<div className={styles.container}>
<div className={styles.formContainer}>
<form
className={styles.form}
ref={form}
onSubmit={sendEmail}
id="form"
>
<h3>Name (required):</h3>
<input type="text" required={true} name="user_name"></input>
<h3>Email (required):</h3>
<input type="email" required={true} name="user_email"></input>
<h3>Phone number (required):</h3>
<input type="number" required={true} name="phone_number"></input>
<h3>Message (optional):</h3>
<textarea name="message"></textarea>
<button type="submit" value="Send">
Submit
</button>
{sentMessage ? <p>{sentMessage}</p> : <p></p>}
</form>
</div>
</div>
);
}
export async function getServerSideProps() {
return {
props: {
USER_ID: process.env.USER_ID,
EMAIL_TEMPLATE_ID: process.env.EMAIL_TEMPLATE_ID,
SERVICE_ID: process.env.SERVICE_ID,
},
};
}
I have a .env.local file with the template id, user id and service id that all work fine locally. I use next-env and dotenv-load in the next.config.js file like so:
dotenvLoad();
const withNextEnv = nextEnv();
module.exports = withNextEnv({
reactStrictMode: true,
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ["#svgr/webpack"],
});
return config;
},
});
I saw some problems online that people had with Gmail and remote email servers, so I switched the account to have no 2 factor authentication and use less secure apps as well. That had no effect.

All you need to do is set up the environment variables in the next.js dashboard then rebuild the site so they take effect.

Related

SvelteKit: cookies.set() In Form Action Not Working

I am trying to implement JWT-based user sessions with SvelteKit, and have mostly been following the explanation for form actions given on their website: https://kit.svelte.dev/docs/form-actions
+page.svelte
<form method="POST" action="?/signIn">
<input type="text" name="name" />
<input type="password" name="password" />
<button type="submit">Submit</button>
</form>
+page.server.svelte
import { fail, redirect } from "#sveltejs/kit";
import { signIn } from "$lib/server/database";
export const actions = {
signIn: async ({ cookies, request }) => {
const data = await request.formData();
const name = data.get("name");
const password = data.get("password");
if (!name || !password) {
return fail(400);
}
try {
cookies.set("jwt", await signIn(name, password));
} catch (error) {
return fail(400);
}
throw redirect(303, "/");
},
};
I have tested my signIn method which I import and use here, and it does return a token when called with the correct credentials. So far, so good. However, I noticed that I don't see any cookies in my developer tools. It seems like the cookies.set() call simply does nothing. I'd like to set the returned JWT as a cookie so that I can authenticate my users, so what am I doing wrong?
In case anybody else has this problem: While the cookie was set as it was supposed to when using Chrome, it wasn't in Safari. I solved this by setting the secure option to false, even though the SvelteKit docs state that this is done automatically on localhost.

How does one POST an AWS S3 hosted contact form using javascript to an AWS api gateway endpoint for processing on a nodejs labmbda function

In advance, thank you for reading this long question. To start with I have this static AWS S3 hosted HTML form that I'd like to use to gather a requester's contact information/question so I can contact them for whatever question they might pose. The HTML for that form looks like this:
<form id="contact-form">
<div class="form-group">
<label>First and Last Name</label>
<input id="name-input" name="name" type="text" class="form-control" required="" placeholder="Enter your name here.....">
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Email</label>
<input id="email-input" name="email" type="email" class="form-control" required="" placeholder="Enter your mail address here.....">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Phone</label>
<input id="phone-input" name="phone" type="phone" class="form-control" required="" placeholder="Enter your phone number">
</div>
</div>
</div>
<div class="form-group">
<label>Subject</label>
<input name="subject" type="text" class="form-control" required="" id="subject" placeholder="Subject">
</div>
<div class="form-group">
<label>Message</label>
<textarea id="message" name="message" class="form-control" required="" placeholder="Write you message here..." style="height:100px;"></textarea>
</div>
<input type="submit"/>
</form>
As you can tell there is absolutely nothing interesting about this form. This form gets processed by some JavaScript that looks like this:
<script async type="text/javascript">
const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
// prevent the form submit from refreshing the page
event.preventDefault();
const { name, email, phone, subject, message } = event.target;
// Use your API endpoint URL you copied from the previous step
const endpoint = "<https://MyApiGatewayEndpoint-east-1.amazonaws.com/test/mailfwd>";
// We use JSON.stringify here so the data can be sent as a string via HTTP
const body = JSON.stringify({
senderName: name.value,
email: email.value,
phone: phone.value,
subject: subject.value,
message: message.value
});
window.alert("Body is " + body);
const requestOptions = {
method: "POST",
body
};
fetch(endpoint, requestOptions)
.then((response) => {
if (!response.ok) throw new Error("Error in fetch");
return response.json();
})
.then((response) => {
document.getElementById("result-text").innerText =
"Email sent successfully!";
})
.catch((error) => {
document.getElementById("result-text").innerText =
"An unkown error occured.";
});
});
</script>
As you can tell this too is in no way interesting. This JavaScript simply grabs the form submit and is supposed to send a POST transaction to my AWS API Gateway endpoint that then passes it along to my NodeJS lambda function and sends me an email using AWS SES. For reference here is what my NodeJS Lambda function looks like:
const aws = require("aws-sdk");
const ses = new aws.SES({ region: "us-east-1" });
exports.handler = async function (event) {
console.log('EVENT: ', event)
// Extract the properties from the event body
const { senderName, senderEmail, senderPhone, subject, message } = JSON.parse(event.body)
const params = {
Destination: {
ToAddresses: ["MyToAddress#whatever.com"],
},
// Interpolate the data in the strings to send
Message: {
Body: {
Text: {
Data: `You just got a message from ${senderName} at phone number ${senderPhone} - ${senderEmail}:
${message}`
},
},
Subject: { Data: `Message regarding ${subject}` },
},
Source: "contactform#whateverelse.com",
};
return ses.sendEmail(params).promise();
};
The problem is when I debug the page during a form submit button click in the Chrome developer tools I get an error that says:
contact.html:459 POST https://s3.us-east-2.amazonaws.com/n.com/%3Chttps://.amazonaws.com/test/mailfwd%3E 405
This confuses me because it looks like the post from the JavaScript is first being sent to my S3 bucket with instructions for the S3 bucket to forward the POST along to my API Gateway EndPoint. I know sending a POST to an S3 bucket from a form submission won't fly Soooooo ....... how do I get my JavaScript to send this post directly to my API Gateway EndPoint. Incidentally, I can send a post directly to this API Gateway EndPoint using curl with the values my NodeJS Lambda function expects and everything works as expected and my "Contact Us" email arrives at my recipient address. This means I know the API Gateway EndPoint will gladly accept a direct post and work happily with my AWS Lambda function. Thanks in advance for any suggestions or answers anyone provides.
-J
Please see my problem description above.
The most telling part of the error message you posted is that it contains %3C and %3E - some characters that have been escaped because they don't normally appear in URLs.
Checking an ASCII table confirms that they are < and > and looking at your code I see this:
const endpoint = "<https://MyApiGatewayEndpoint-east-1.amazonaws.com/test/mailfwd>";
That's not a well-formed URL, so the browser is trying to guess what you mean by it. It's deciding that it's a relative URL, and generating a full URL by combining it with the URL of the current page, as it would if you just specified a file name like "process.php".
What you actually wanted was an absolute URL, which just looks like this:
const endpoint = "https://MyApiGatewayEndpoint-east-1.amazonaws.com/test/mailfwd";
Possibly you looked at some sample code with something like <your URL here> and misunderstood.

How do I create a cookie in svelte and access it?

I am trying to create a cookie in svelte (and I am also using svelte kit) and access it. I am want to use the cookie for authentication purposes, more specifically, to store a JWT Token.
I am tried implementing pure JS code, such as getCookie() and setCookie() as shown here W3Schools - JavaScript Cookies. But I can't get access to the document. I have also tried serialize from the cookie npm package, as shown below, and I have also tried using browser as shown below.
import { serialize } from "cookie";
import { browser } from '$app/environment';
You can e.g. set a cookie in a form action. If you want to be able to read it in the browser, you have to disable HttpOnly (in general you should avoid this, as it makes cross site scripting vulnerabilities worse).
A simple example:
<!-- +page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms';
export let form: { error?: string; } | null;
</script>
<form method="post" use:enhance>
<label>Login <input type="text" name="login" /></label>
<label>Password <input type="password" name="password" /></label>
{#if form?.error}<p>{form.error}</p>{/if}
<button type="submit">Login</button>
</form>
// +page.server.ts
import { invalid, redirect } from '#sveltejs/kit';
import type { Actions } from './$types';
export const actions: Actions = {
default: async ({ request, cookies }) => {
const formData = await request.formData();
const login = formData.get('login');
const password = formData.get('password');
if (login == 'admin' && password == '...') {
cookies.set(
'auth', '42',
{
path: '/',
maxAge: 60 * 60 * 24 * 365,
httpOnly: false, // <-- if you want to read it in the browser
},
);
throw redirect(302, '/');
}
return invalid(400, { error: 'Invalid login or password' });
},
}
The cookie can be read from document.cookie, note that this will throw an error during SSR, so you have to check browser or read it in onMount.

Nuxt.js page reloading on for submission even with stop.prevent

I've been reading some questions about this exact same topic like but none of them seems to be working for me and I can't spot the error.
I have this form:
<template>
<div class="container">
<form #submit.stop.prevent="submit">
<input v-model="name" type="text" />
<input v-model="email" type="text" />
<button type="submit">Submit</button>
</form>
</div>
</template>
And the following script
<script>
export default {
data() {
return {
name: '',
email: ''
}
},
methods: {
async submit() {
const res = await this.$axios.request({
url: 'locahost:3000/404', // This route doesn't exists
method: 'post',
data: this.$data
})
console.log(res.status)
}
}
}
</script>
As you can see, there are more than one input in the form and I'm using stop.prevent when binding the submit event in the form.
I want to treat any possible errors in the axios request in the script part and update the page based on that (showing an error div or whatever) but without reloading it. However, the page reloads and is going to a 404 error page.
I'm using Nuxt 2.12.2 and I can't see what I'm doing wrong. Any help would be appreciated.
Thanks all!
You can omit the form behaviour by only using the data in your submit method and trigger it by #click on the button without any submit type, like this :
<template>
<div class="container">
<form>
<input v-model="name" type="text" />
<input v-model="email" type="text" />
<button #click="() => submit()">Submit</button>
</form>
</div>
</template>
Like this you will avoid any kind of side effect from the form as you don't need any form data in your axios request...
Ok, I found the answer just by trial and error and it was easier than I thought... It was only about unhandled promise rejection. As I'm using async/await I need to treat exceptions correctly and I was not doing that, the rejection was being propagated and the error handled by nuxt. So changing my code to:
<script>
export default {
data() {
return {
name: '',
email: ''
}
},
methods: {
async submit() {
try {
const res = await this.$axios.request({
url: 'locahost:3000/404', // This route doesn't exists
method: 'post',
data: this.$data
})
console.log(res.status)
} catch (err) {
console.log(err)
}
}
}
}
</script>
That will prevent the error to be handled elsewhere and resulting in a redirection to a 404 page or whatever.

How to emit inputs on change using socket.io?

I'm working on a chat style app using React and socket.io, and I want to implement something where a client can see the input being typed by the other client in realtime. I'm using onChange on the input to update the state and emit the message at the same time, but that only sends messages one letter at a time to the server, and deletions don't work at all.
Here's the frontend with extra code omitted:
this.state = {
text: '',
name: '',
messages: []
}
componentDidMount() {
socket.on('RECIEVE_MESSAGE', function(msg) {
this.setState({
messages: [...this.state.messages, msg]
})
})
}
onInputChange(event) {
this.setState({
text: event.target.value
})
socket.emit('example_message', this.state.text);
this.setState({
messages: [...this.state.messages, this.state.text]
})
}
return (
<div>
<form type="text" onSubmit={this.handleSubmit}>
<input
type="text"
className="text-input"
id="name-input"
name="text-input"
required="required"
placeholder="text"
//used to save end result
value={this.state.text}
onChange={this.onInputChange}></input>
{/* <button className="next-btn"> NEXT </button> */}
<button onClick={this.sendSocketIO}>Send Socket.io</button>
</form>
<p>{this.state.text}</p>
<p>{this.state.messages}. </p>
</div>
)
And the backend:
io.on('connection', client => {
console.log('Socket connected: ', client.id);
//recieves the message from the client, and then re-emits to everyone
client.on('SEND_MESSAGE', data => {
data.message = validate.blacklist(data.message, ['<','>','&','"','/']);
io.emit('RECEIVE_MESSAGE', data);
});
I'd like to render to the DOM a live feed of what the other client is typing, and update it with every character and character deletion.
You are emitting with:
socket.emit('example_message', this.state.text)
and handling with:
client.on('SEND_MESSAGE', data...
Use the same name for the message to emit and then handle on the server.

Categories