I am using an angular controller to send an http post request to my express route and then data is being sent to my gmail client using nodemailer. The $http request works and I do receive emails in my gmail clients however when I try to log information to my console or create javascript alerts nothing happens. Ideally when a user sends an email through the contact form I would like two alerts. 1.) email is being sent and 2.) email has been sent! The problem is that the callback functions in angular won't allow me to do so? any ideas? Cheers!
/* server.js */
var express = require('express');
var app = express();
var http = require('http');
var httpServer = http.Server(app);
var nodemailer = require('nodemailer');
var bodyParser = require('body-parser');
app.use(bodyParser.json({}));
app.use(express.static(__dirname + '/public'));
app.use('/', express.static(__dirname + '/public'));
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
var server = app.listen(9000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'solarcode94#gmail.com',
pass: '********'
}
});
app.route('/').post(function(req, res) {
var data = req.body;
transporter.sendMail({
from: data.contactEmail,
sender: data.contactEmail,
to: 'solarcode94#gmail.com',
subject: 'Message from ' + data.contactName,
text: data.contactEmail + 'swws' + data.contactMsg
});
});
<!-- index.html -->
<!DOCTYPE html>
<html lang="en" ng-app="mailingApp">
<head>
<meta charset="UTF-8">
<title>nodejs mailing</title>
<script src="http://code.angularjs.org/1.2.13/angular.js"></script>
<script src="node-email-controller.js"></script>
</head>
<body ng-controller="mailingCtrl">
<form name="contactForm" data-ng-submit="sendMail()" novalidate>
Name: <input type="text" data-ng-model="contactName">
Email: <input type="text" data-ng-model="contactEmail">
Message: <textarea ng-model="contactMsg" columns="1" required></textarea>
<button type="submit">Send</button>
</form>
</body>
</html>
/* angular controller */
var mailingApp = angular.module('mailingApp', []);
mailingApp.controller('mailingCtrl', ['$scope', '$http', function($scope, $http){
$scope.sendMail = function(){
var data = ({
contactName : this.contactName,
contactEmail : this.contactEmail,
contactMsg : this.contactMsg
});
$http.post('/', data).
then(function(response) {
}, function(response) {
});
};
}]);
If you are familiar with nodemailer or express sometimes I end up receiving two emails per form submission and have no idea how to solve that. Thanks!
First, this needs some kind of a response returned:
app.route('/').post(function(req, res) {
var data = req.body;
transporter.sendMail({
from: data.contactEmail,
sender: data.contactEmail,
to: 'solarcode94#gmail.com',
subject: 'Message from ' + data.contactName,
text: data.contactEmail + 'swws' + data.contactMsg
});
});
Second, you could do the alerts like this:
$scope.sendMail = function(){
var data = ({
contactName: this.contactName,
contactEmail: this.contactEmail,
contactMsg: this.contactMsg
});
alert('Sending the email');
$http.post('/', data).then(function(response) {
// provided that the `transporter.sendMail` returned a good response
alert('The email was sent');
}, function(response) {
// provided that the `transporter.sendMail` returned a bad response
alert('The email did not send');
});
};
Related
I'm trying to add a contact form in my website using nodemailer.
With plain-text, the email was sent (with the cmd node server.js), but since I have added a form in my html and tried to send the "req.bodies" using a route, it doesn't work anymore and I have the following error : Error: Missing credentials for "PLAIN".
Here are my codes :
Index.js
var express = require("express");
var router = express.Router();
const nodemailer = require("nodemailer");
/* GET home page. */
router.get("/", function (req, res, next) {
res.render("index", { title: "Express" });
});
router.post("/send-email", async function (req, res, next) {
"use strict";
var email = req.body.email;
var name = req.body.name;
var message = req.body.message;
var transporter = nodemailer.createTransport({
// host: "smtp.gmail.com",
service: "gmail",
// secure : false,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
console.log("message :", req.body.message, "email :", req.body.email);
// send mail with defined transport object
var mailOptions = {
from: email,
to: process.env.EMAIL,
subject: "Nouveau mail contact de " + name, // Subject line
text: name + "0102030405" + message,
};
transporter.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
} else {
res.redirect("/");
}
});
});
module.exports = router;
Server.js
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const port = 3000;
require("dotenv").config();
app.use(bodyParser.json());
const nodemailer = require("nodemailer");
app.listen(port, () => {
console.log(`Server running on ${port}`);
});
app.use("/index", require("./routes/index"));
// let transport = nodemailer.createTransport({
// service: "gmail",
// auth: {
// user: process.env.EMAIL,
// pass: process.env.PASSWORD,
// },
// });
// let mailOptions = {
// from: '"Fred Foo đź‘»" <process.env.EMAIL>', // sender address
// to: "process.env.EMAIL", // list of receivers
// subject: "Hello âś”", // Subject line
// text: "Hello world?", // plain text body
// html: "<b>Hello world?</b>", // html body
// };
// transport.sendMail(mailOptions, function (err, data) {
// if (err) {
// console.log("Error Occurs");
// } else {
// console.log("Email sent !!");
// }
// });
html
<form action="/send-email" method="POST">
Your Name:
<input type="text" name="name">
Email Address:
<input type="email" name="email" placeholder="Email">
Message:
<textarea name="message"></textarea>
<input type="submit" value="Submit">
</form>
Body-Parser doesn't seem to work because it is strikeout.
“less secure” apps is enabled on my gmail account
Thank you very much for your help !
EDIT : I think it's because it doesn't recognize my process.env because when I directly write them, it works.
I put my file .env in the same directory but it still does not recognize them.
I am trying to output a message of 'XYZ is typing' whenever a user begins typing but I can't seem to fix my code. I feel as if the 'socket.broadcast.emit' in the App.JS of my code is the issue but I am not sure. If possible can somebody point me in the right direction to helping me fix my chat app. Thanks in advance!
Index.HTML
<!doctype html>
<html>
<head>
<title>Chit Chat</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<ul id="messages"></ul>
<div id="typing"></div>
<form action="">
<input id="username" placeholder="Username" type="text" />
<input id="message-box" autocomplete="off" type="text" placeholder="Type Message" />
<button id="button">Send</button>
</form>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="/js/scripts.js" charset="utf-8"></script>
</body>
</html>
App.JS (Server)
var express = require('express');
var app = require('express')();
var bodyParser = require('body-parser');
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}))
app.use(express.static('./public'));
app.get('/', function(req, res){
res.sendFile(__dirname + '/views/index.html');
});
var port = process.env.PORT || 3000;
http.listen(port, function(){
console.log('listening on ' + port);
});
// Socket.io
io.on('connection', function(socket) {
// when the client emits 'new message', this listens and executes
socket.on('new message', function(data) {
// we tell the client to execute 'new message'
io.sockets.emit('new message', data);
});
// when the client emits 'typing', we broadcast it to others
socket.on('typing', function(data){
socket.broadcast.emit('typing', data);
});
});
Scripts.JS
console.log('Loaded');
var socket = io();
$(function (){
chat();
emitEvents();
isTyping();
});
function chat() {
$('form').submit(function(e){
var message = {
username: $('#username').val(),
message: $('#message-box').val()
}
e.preventDefault();
socket.emit('new message', message);
$('#message-box').val('');
});
}
function isTyping() {
$('#message-box').keypress(function() {
socket.emit('typing', $('#username').val());
});
}
function emitEvents() {
socket.on('typing', function(data){
console.log(data);
$('#typing').append($('<p>').text(data + 'is typing'));
});
socket.on('new message', function(data){
$('#messages').append($('<li>').text(data.username + ': ' +
data.message));
});
}
I tried your code and it's working. I have created a live example.
I made 2 modifications in scripts.js, so the typing message will appear only once during the typing.
function emitEvents() {
socket.on('typing', function(data){
console.log(data);
$('#typing').html($('<p>').text(data + ' is typing')); // update
});
socket.on('new message', function(data){
$('#typing').html($('<p>').text('')); // update
$('#messages').append($('<li>').text(data.username + ': ' + data.message));
});
}
The code socket.broadcast.emit means sending to all clients except sender.
Check out the Socket.IO cheatsheet.
I am trying to use imap to search emails in my gmail inbox. It is going to be server side mail parser. To do so, I used express and I want to receive the input of users (from search field) using express. However, all the solutions I searched in the internet use app.post and bring me to a new page. I don't want to show any thing new in user interface. I just want to receive the input of user and give it to a function which performs imap.search. Any help? Here is the code:
index.htm
<!doctype html>
<html>
<body>
<form action="http://127.0.0.1:8081/process_post" method="POST">
Search: <input type = "text" name = "Search_value"> <br>
<input type = "submit" value = "SEARCH">
</form>
</body>
</html>
test.js
var express = require('express')
var bodyParser = require('body-parser');
var app = express()
app.use(express.static('public'));
// use body parser to easy fetch post body
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
var Imap = require('imap'),
inspect = require('util').inspect,
MailParser = require("mailparser").MailParser;
var imap = new Imap({
user: '***#gmail.com',
password: '*****',
host: 'imap.gmail.com',
port: 993,
tls: true
});
var fs = require('fs'), fileStream;
function openInbox(cb) {
imap.openBox('INBOX', true, cb);
}
// route to '/index.htm' to return the html file
app.get('/index.htm', function (req, res) {
res.sendfile('index.htm');
});
//route that receives the post body and returns your computation
app.post('/process_post', function (req, res) {
passtoserver(req.body, res);
});
app.listen(8081);
function passtoserver(parms, res) {
//get the parameters based on input name attribute from the html
//and parse strings to numbers
var m = parms.Search_value;
// res.writeHead(200, { 'Content-Type': 'text/html' });
res.end();
openInbox(function(err, box) {
if (err) throw err;
imap.search([ 'ALL', ['FROM', m] ], function(err, results) {
var f = imap.fetch(results, {
bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)',
struct: true
});
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
stream.once('end', function() {
console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
});
});
});
}
imap.connect();
After submiting the user input, a new rout called process-post will ope. How to avoid this?
You can try it with:
https.request() API?
http.request() for secure protocal
I am trying to make notification system. To demonstrate this, User 1 is sending friend request to User 2. I am using express.js, angularjs and socket.io. On click of the button User1 sends request. On end of User2, there is a socket,on() which is listening on friend-request event. But when I am broadcasting, the other user is not able to receive any message.
app.js (Node Server File)
var express = require('express'),
app = express();
var port = process.env.PORT || 3000;
var io = require('socket.io').listen(app.listen(port));
require('./config')(app,io);
require('./routes')(app,io);
config.js
// This file handles the configuration of the app.
// It is required by app.js
var express = require('express');
module.exports = function(app, io){
// Set .html as the default template extension
app.set('view engine', 'html');
// Initialize the ejs template engine
app.engine('html', require('ejs').renderFile);
// Tell express where it can find the templates
app.set('views', __dirname + '/views');
// Make the files in the public folder available to the world
app.use(express.static(__dirname + '/public'));
};
routes.js (Emitting Friend Request From this File)
var gravatar = require('gravatar');
var mysql = require('mysql');
// This is needed if the app is run on heroku:
var connection = mysql.createConnection({
host : "localhost",
user : "root",
password : "",
database : "two_way_demo"
});
connection.connect(function(error){
if(error)
{
console.log("Problem with MySQL"+error);
}
else {
console.log("Connected with Database");
}
});
module.exports = function(app,io){
app.get('/',function(req,res){
res.render('index');
});
app.get('/create', function(req,res){
// Generate unique id for the room
var id = Math.round((Math.random() * 1000000));
// Redirect to the random room
res.redirect('/chat/'+id);
});
app.get('/home/:id', function(req,res){
// Render the chant.html view
res.render('home');
});
// Initialize a new socket.io application, named 'chat'
var chat = io.on('connection', function (socket) {
socket.on('get-user-id',function(data){
connection.query("SELECT * from user_info WHERE email='"+data.userEmail+"'",function(err,rows){
if(err)
{
console.log("Problem with MySQL"+err);
}
else
{
//console.log(rows);
JSON.stringify(rows);
socket.emit('user-id',rows);
}
});
});
socket.on('send-request',function(data){
console.log(data);
*********************************************************************
// Tried the emit here but its not working
//io.emit('friend request', {
// receiverid: data.receiverid
//});
*********************************************************************
});
});
}
angular-code.js (angular code file)
$(function () {
var app = angular.module("notificationApp", []);
app.controller("chatCTRL", ["$scope", "$http", "$interval", function ($scope, $http, $interval) {
// connect to the socket
//var socket = io();
//socket.on('connect', function () {
// io.on('friend request', function (data) {
// alert("here")
// });
//});
$scope.senderId = Number(window.location.pathname.match(/(\d+)$/)[1]);
$scope.sendrequest = function (senderid, receiverid) {
var socket = io();
socket.on('connect', function () {
socket.emit('send-request', {
senderid: senderid,
receiverid : receiverid
});
});
}
}]);
app.controller("loginCTRL", ["$scope", "$http", "$interval", "$window", function ($scope, $http, $interval, $window) {
$scope.sendLogin = function () {
var socket = io();
socket.on('connect', function () {
socket.emit('get-user-id', {
userEmail: $scope.hisEmail
});
});
socket.on('connect', function () {
socket.on('user-id', function (data) {
$scope.UserId = data[0].user_id;
$window.location = "http://localhost:3000/home/" + $scope.UserId;
});
});
}
}]);
}());
home.html
<!DOCTYPE html>
<html ng-app="notificationApp">
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body ng-controller="chatCTRL">
<h1>welcome</h1>
<div id="createbutton">
<div id="little"><button ng-click="sendrequest(senderId,6)">Send Friend Request to User#6</button></div>
</div>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="../angular/angular.js"></script>
<script src="../angular/common_angular.js"></script>
</body>
</html>
Some client side architecture things:
In most cases on angular client side it is better to move your socket connection to service. And make connection when service is initialized (service is singleton, therefore there will be one connection on start) and inject this service in your controllers.
It may be convenient to create some parent abstract controller with
all socket listeners, therefore whether angular controller is active, all listeners are watching. When parent controller get data from socket it can broadcast it to children controllers
In your commented code you have:
//var socket = io();
//socket.on('connect', function () {
// io.on('friend request', function (data) {
// alert("here")
// });
//});
change it to this (if you make connection in service you should omit connect part):
var socket = io();
socket.on('connect', function () {
socket.on('friend request', function (data) {
alert("here")
});
});
Backend:
In your commented code you have:
//io.emit('friend request', {
// receiverid: data.receiverid
//});
You should use socket's from var chat = io.on('connection', function (socket) {... to emit instead of io.emit
Create array variable where you will store all your sockets with users id before connection part:
var socketList = [];
var chat = io.on('connection', function (socket) {
socketList.push({id:someId,socket:socket})
...
}
Now in send-request user should send id of his frient (we have to know which user should be notified- of course we can notify everybody):
socket.on('send-request',function(data){
socketList.forEach(function(soc){
if(soc.id === someId){
soc.socket.emit('friend request', {
receiverid: data.receiverid
})
}
});
Also i don't like this part receiverid: data.receiverid, because it means that taget user get id of receiver from receiver client side. And this may be unsafe (user can change his id and send some other id). I prefere to create id in server side and when user A send notification to user B I get user A id from server variable.
Some time age I create simple prototype of chat application (angular and express), there are some things which I mention here. I you have still problems with your application go there and check my code :
https://github.com/uhlryk/chat-prototype
I am trying to understand where to locate the logic to send an email via a contact form in my Angular App (using angular-fullstack MEAN stack from Yeoman).
I can add the logic to send an email in the app.js file on the server side using nodemailer and sendgrid and everything works and an email is sent every time I refresh the server, however I am a little fuzzy on where to place the logic so that it only gets sent once the form is submitted and it hits the server side.
This is what the create action looks like on the Express JS side...
exports.create = function(req, res) {
Contact.create(req.body, function(err, contact) {
if(err) { return handleError(res, err); }
return res.json(201, contact);
});
};
Here is the code in app.js that is working, but obviously not in the right place...
var nodemailer = require('nodemailer');
var sgTransport = require('nodemailer-sendgrid-transport');
var options = {
auth: {
api_user: 'username', // 'SENDGRID_USERNAME' - Recommended to store as evn variables
api_key: 'password', // 'SENDGRID_PASSWORD'
}
};
var mailer = nodemailer.createTransport(sgTransport(options));
var email = {
to: 'sendto#email.com',
from: 'sendfrom#email.com',
subject: 'Test Email',
text: 'Awesome Email',
html: '<b>Bold and Awesome Email</b>'
};
mailer.sendMail(email, function(err, res) {
if (err) {
console.log(err)
}
console.log(res);
});
Coming from a rails background my initial thought is to stick the logic in the create action so that if the object is created successfully the email gets sent. Is this a correct way of thinking about it in this scenario...I am new to the MEAN stack.
Thanks for any help...
You need to create a route on the server that you can post form values to from Angular using $http.post.
The following lets you enter details in an Angular form. The form is then posted to Node where the req.body values are extracted and added email object. The email is then send by SendGrid.
SERVER.JS
var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
var dotenv = require('dotenv');
dotenv.load(); //load environment variables from .env into ENV (process.env).
var sendgrid_username = process.env.SENDGRID_USERNAME;
var sendgrid_password = process.env.SENDGRID_PASSWORD;
var sendgrid = require('sendgrid')(sendgrid_username, sendgrid_password);
var email = new sendgrid.Email();
var app = express();
app.use(bodyParser.json()); //needed for req.body
app.set('port', process.env.PORT || 3000);
app.use(express.static(__dirname + '/public'));
app.post('/email', function(req, res) {
email.addTo(req.body.to);
email.setFrom(req.body.from);
email.setSubject(req.body.subject);
email.setText(req.body.text);
email.addHeader('X-Sent-Using', 'SendGrid-API');
email.addHeader('X-Transport', 'web');
sendgrid.send(email, function(err, json) {
if (err) {
return res.send("Problem Sending Email!!!!");
}
console.log(json);
res.send("Email Sent OK!!!!");
});
});
var server = http.createServer(app);
server.listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port') ) ;
});
INDEX.HTML
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8">
<title></title>
<!-- CSS -->
</head>
<body ng-controller="MainCtrl">
<form name="emailForm">
<div class="group">
<input type="email" name="to" ng-model="email.to" ng-required="true">
<label>To</label>
</div>
<div>
<input type="email" name="from" ng-model="email.from" ng-required="true">
<label>From</label>
</div>
<div>
<input type="text" name="subject" ng-model="email.subject" ng-required="true">
<label>Subject</label>
</div>
<div>
<textarea ng-model="email.text" name="text" placeholder="Enter Text Here.."></textarea>
</div>
<button id="emailSubmitBn" type="submit" ng-click="submitEmail()">
Submit
</button>
</form>
<!-- JS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
CLIENT SIDE APP.JS
angular.module('myApp', [])
.controller('MainCtrl', function($scope, $http) {
$scope.submitEmail = function() {
console.log("TEST");
//Request
$http.post('/email', $scope.email)
.success(function(data, status) {
console.log("Sent ok");
})
.error(function(data, status) {
console.log("Error");
})
};
});