How to Build an email scheduler with Express, vue, nodemailer, node-cron and MongoDB

Toluarejibadey
4 min readApr 15, 2023

--

This is the front-end using vue2 which covers this article https://medium.com/@toluarejibadey/how-to-build-an-email-scheduler-with-express-vue-nodemailer-node-cron-and-mongodb-c9e99e1b10e1

Step #1: Go to your cmd and type

vue create ui

install vue 2 after installation has finished inside your vue folder install

npm install vuelidate vue-notification axios bootstrap

add this in your main.js file

import Vue from 'vue'
import App from './App.vue'
import router from './router'

import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap'
import Vuelidate from "vuelidate";
import Notifications from 'vue-notification'
import 'jquery/src/jquery.js'
import 'bootstrap/dist/js/bootstrap.min.js'
import VueSweetalert2 from 'vue-sweetalert2';
import 'sweetalert2/dist/sweetalert2.min.css';

Vue.config.productionTip = false

Vue.use(Notifications)


Vue.use(Vuelidate);
Vue.use(VueSweetalert2);
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

Step #2: Add this in your vue file

here we are just getting our form input and sending it to the backend


<template>

<body>
<div class="container">
<div class="row justify-content-center">

<div class="col-xs-12 col-sm-12 col-md-8 col-lg-6 column col-sm-offset-0 col-md-offset-2 col-lg-offset-3">
<h3 class="justify-content-center">Schedule email</h3>
<hr />
<form class="form-horizontal">
<div>
<label>
to
</label>
<input
type="text"
:class="{ error: $v.to.$error }"
@input="$v.to.$touch()"
class="form-control"
placeholder="qwe@gmail.com"
v-model.trim="to"
>
<div v-if="$v.to.$dirty">
<p
class="error-message"
v-if="!$v.to.email"
>
Please enter a valid email address.
</p>
<p
class="error-message"
v-if="!$v.to.required"
>
Email must not be empty.
</p>
</div>
</div>
<div>
<label>
subject
</label>
<input
type="text"
:class="{ error: $v.subject.$error }"
@input="$v.subject.$touch()"
class="form-control"
placeholder="enter subject"
v-model.trim="subject"
>
<div v-if="$v.subject.$dirty">

<p
class="error-message"
v-if="!$v.subject.required"
>
field is required
</p>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div>
<label>
minute
</label>
<input
type="text"
:class="{ error: $v.minute.$error }"
@input="$v.minute.$touch()"
class="form-control"
placeholder="0-59"
v-model.trim="minute"
>
<div v-if="$v.minute.$dirty">

<p
class="error-message"
v-if="!$v.minute.required"
>
field is required
</p>
</div>
</div>
</div>
<div class="col-md-6">
<div>

<label>
hour
</label>
<input
type="text"
:class="{ error: $v. hour.$error }"
@input="$v. hour.$touch()"
class="form-control"
placeholder="0-23"
v-model.trim=" hour"
>
<div v-if="$v. hour.$dirty">

<p
class="error-message"
v-if="!$v. hour.required"
>
field is required.
</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div>
<label>
week
</label>
<select
name
class="form-control"
id
:class="{ error: $v. week.$error }"
@input="$v. week.$touch()"
placeholder="Sunday"
v-model.trim="week"
>

<option value="Monday">Monday</option>
<option value="Tuesday">Tuesday</option>
<option value="Wednesday">Wednesday</option>
<option value="Thursday">Thursday</option>
<option value="Friday">Friday</option>
<option value="Saturday">Saturday</option>
<option value="Sunday">Sunday</option>

</select>

<div v-if="$v. week.$dirty">

<p
class="error-message"
v-if="!$v. week.required"
>
field must not be empty.
</p>
</div>
</div>
</div>
<div class="col-md-6">
<div>
<label>
month
</label>
<select
name
class="form-control"
id
:class="{ error: $v. month.$error }"
@input="$v. month.$touch()"
placeholder="Month"
v-model.trim=" month"
>

<option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
<option value="April">April</option>
<option value="May">May</option>
<option value="June">June</option>
<option value="July">July</option>
<option value="August">August</option>
<option value="September">September</option>
<option value="Ocotber">October</option>
<option value="November">November</option>
<option value="December">December</option>

</select>

<div v-if="$v. month.$dirty">

<p
class="error-message"
v-if="!$v. month.required"
>
field must not be empty.
</p>
</div>
</div>
</div>
</div>

<div>
<label>
day
</label>
<input
type="text"
:class="{ error: $v. day.$error }"
@input="$v. day.$touch()"
class="form-control"
placeholder="0-31"
v-model.trim=" day"
>
<div v-if="$v. day.$dirty">

<p
class="error-message"
v-if="!$v. day.required"
>
field must not be empty.
</p>
</div>
</div>
<div>
<label>
message
</label>
<textarea
type="text"
rows="5"
:class="{ error: $v.html.$error }"
@input="$v.html.$touch()"
class="form-control"
id="textarea"
name="textarea"
placeholder="enter message"
v-model.trim="html"
>
</textarea>
<div v-if="$v.html.$dirty">

<p
class="error-message"
v-if="!$v.html.required"
>
field must not be empty.
</p>
</div>
</div>
<div>
<label>
Attachment
</label>
<input
type="file"
@change="onFileSelected"
name="file"
class="form-control"
ref="files"
>

</div>
<br>
<div class="d-flex justify-content-center">
<button
:disabled="$v.$invalid"
type="submit"
id="form-submit"
class="btn btn-info btn-sm"
@click.prevent="send"
>Submit</button>
</div>

</form>
</div>
</div>
</div>

</body>

</template>

here’s the script tag and style


<script>
import axios from "axios";
import { required, minLength, between, email } from "vuelidate/lib/validators";

export default {
name: "App",
components: {},
data() {
return {
message: "",
to: "",
subject: "",
// second: "",
minute: "",
hour: "",
week: "",
month: "",
day: "",
html: "",
file: null
};
},
// validation for forms
validations: {
to: {
required,
email
},
html: {
required
},
minute: {
required
},
day: {
required
},
month: {
required
},
week: {
required
},
hour: {
required
},

subject: {
required
}
},

methods: {
// get the uploaded file
onFileSelected(event) {
this.selectedFile = event.target.files[0];
this.fileName = event.target.files[0].name;
},
// we us form data cause we are sending attachment
async send() {
let data = new FormData();
data.append("to", this.to);
data.append("file", this.selectedFile, this.selectedFile.name);
data.append("html", this.html);
data.append("minute", this.minute);
data.append("hour", this.hour);
data.append("month", this.month);
data.append("day", this.day);
data.append("week", this.week);

data.append("subject", this.subject);

const response = await axios.post(
"http://localhost:3000/api/crons",
data
);
this.$notify(`email sent`);
}
}
};
</script>
<style>
input:focus {
outline: none;
}
.error {
border: 1px solid red;
}
.error-message {
color: red;
}
</style>

--

--