Adapt Nodemailer as a REST service for AngularJS - javascript

I have been struggling with the logic client/server side to adapt the Nodemailer component https://github.com/andris9/Nodemailer to my angular project.
Ihe only source i have seen close from what i want to do is here from V31.
But i am not sure how to create an "end point server side" as it is explained in the post and the user did not share his code ^^
What i want is to create an angular service for the nodemailer logic and be able to call it for a specific controller that will have my data to send.
Do i need express server to use nodemailer? in the Nodemailer-master the file full.js is capable of sending email on her own
'use strict';
var nodemailer = require('nodemailer');
// Create a SMTP transporter object
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'myemail',
pass: 'mypass'
}
});
console.log('SMTP Configured');
// Message object
var message = {
};
console.log('Sending Mail');
transporter.sendMail(message, function (error, info) {
if (error) {
console.log('Error occurred');
console.log(error.message);
return;
}
console.log('Message sent successfully!');
console.log('Server responded with "%s"', info.response);
});
So again i want to be able to call the 'sending email' method in this full.js file in my $scope..
As you can guess my misunderstanding of the server/client side logic holds me back to do or ask the right questions, but thx for you patience ;)
my data structure looks like :
client side = root/app/js/
(where i have service.js and controllers.js).
Server side? root/node-modules/nodemailer/
(as on github)

Related

Passing Vue.js form data to Nodemailer script with Axios

I have some form data in one of my Vue components that I want to pass on to my Nodemailer script so that data can be sent as an email. I'm trying to use Axios to do this.
Nothing is happening though as I don't actually know what I'm doing!
The Nodemailer script I have set up works when I execute the file in the command line. What I need is for it to execute when the form in my Vue.js component is submitted.
Here is my Nodemailer script -
"use strict";
const nodemailer = require("nodemailer");
require('dotenv').config();
// async..await is not allowed in global scope, must use a wrapper
async function main() {
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true, // true for 465, false for other ports
auth: {
user: process.env.user, // generated ethereal user
pass: process.env.password, // generated ethereal password
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: process.env.user, // sender address
to: process.env.email, // list of receivers
subject: 'Translation Suggestion', // Subject line
text: "Hello world?", // plain text body
html: "<p>Traditional: <br> Simplified: <br> Pinyin: <br> English: "
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
main().catch(console.error);
And the function being called upon submit in my form component -
<button type="submit" #click="sendEmail" class="form__btn">Suggest</button>
sendEmail () {
axios.post("localhost:3000/send-translation-suggest-email", () => {
this.traditional,
this.simplified,
this.pinyin,
this.english
})
}
To create a REST-API with express.js, first initialize a node.js-project (npm init [-y]). Then you install express.js (npm install express).
When you have your setup, you can create an index.js-file, the server. In it, you will have to adapt the content of the express Hello World example, so that the route it accepts is not GET / but POST /send-translation-suggest-email. Then make sure your server listens to port 3000 (as you specified in the client-side code).
In the listener to POST /send-translation-suggest-email, you can call the main-method from your other file (make sure to import the file properly, with node.js's require-syntax).
Then, you can call the backend server from the frontend as you wished.

Error: Connection timeout at SMTPConnection._formatError

Error: Connection timeout at SMTPConnection._formatError, don't know what is wrong, can't send mails,please help me.
am trying to send a mail using nodemailer, but i keep getting this error in my console
Error: Connection timeout
at SMTPConnection._formatError (/home/codabae/Desktop/mailmonster/Backend/v1/node_modules/nodemailer/lib/smtp-connection/index.js:784:19)
at listOnTimeout (internal/timers.js:531:17)
at processTimers (internal/timers.js:475:7) {
code: 'ETIMEDOUT',
command: 'CONN'
}
this is my api
here i don't know what am doing wrong, i getting the details from the mongodb and am filling it in the nodmailer fields, i really don't know what am doing wrong.
router.post('/', auth, (req, res) => {
const { to, cc, bcc, subject, message, attachment, smtpDetails } = req.body;
if (!to || !subject || !message || !smtpDetails) return res.status(400).send('input cannot be empty')
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '...#gmail.com',
pass: '...'
}
});
let mailOptions = {
from: '...#gmail.com',
to: to,
cc: cc,
bcc: bcc,
subject: subject,
text: `${message}`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
res.send('mail not sent')
} else {
console.log('Email sent: ' + info.response);
res.send('mail sent')
}
});
module.exports = router;
The part of the error message to focus on here is SMTPConnection._formatError. You are receiving this error because the transport configuration variables are not correct. You need the following variables, with correct values for each.
There are additional variables that can be used, but based on the fields in your code, the following configuration should work fine. If you need additional info, you can always reference the Nodemailer documentation.
//transport configuration for user a site server to send an email.
let transporter = nodemailer.createTransport({
// This is the SMTP mail server to use for notifications.
// GCDS uses this mail server as a relay host.
host: "smtp.gmail.com",
// SMTP is unlike most network protocols, which only have a single port number.
// SMTP has at least 3. They are port numbers 25, 587, and 465.
// Port 25 is still widely used as a **relay** port from one server to another.
// Port for SSL: 465
// Port for TLS/STARTTLS: 587
port: 465,
// if true the connection will use TLS when connecting to server. If false (the
// default) then TLS is used if server supports the STARTTLS extension. In most
// cases set this value to true if you are connecting to port 465. For port 587 or
// 25 keep it false
secure: true, // use TLS
auth: {
// Your full email address
user: process.env.SMTP_TO_EMAIL,
// Your Gmail password or App Password
pass: process.env.SMTP_TO_PASSWORD
}
});
You mentioned filling these in using some sort of information from MongoDB. I cannot see from where you are getting the variables and values in your configuration, but you may need to use a different source or update your query if you are pulling the values from a database.
NOTE:
Another common issue to be aware of involves using the Gmail password, which cannot be used if your account has 2FA enabled. In this case you must generate a unique App Password by following these guidelines from Google.

How to get nodemailer to work with 2LO for service accounts?

I have followed the instructions on the nodemailer site to the letter, but OAuth2 for google service accounts simply does not work for me.
Either I get ECONN timeouts when setting "host" to mail.google.com or some combination of "401, user/pwd not accepted, can not create access token" errors when using smtp.gmail.com as the host.
I've used this as my template:
http://nodemailer.com/smtp/oauth2/#example-4
I've set up a service account: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I've enabled the gmail api.
I've created tokens that validate:
https://www.googleapis.com/oauth2/v1/tokeninfo
I have also tried the xoauth2 npm package to generate tokens and failed...
I also tried the answer in this question, but still no luck...
There seems to be an endless supply of answers for 3LO, but none that I've tried for 2LO that work. Now, having said all that.
var nodemailer = require("nodemailer");
var { google } = require("googleapis");
var accessToken;
var expires;
var key = require(“path/to/secrets.json");
var privateKey = key.private_key;
var jwtClient = new google.auth.JWT(key.client_email, null, key.private_key, ["https://mail.google.com/"], null);
jwtClient.authorize(function(err, tokens) {
if (err) {
return;
} else {
token = tokens
accessToken = tokens.access_token //this **IS** a valid token
expires = tokens.expiry_date
}
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: "OAuth2",
user: key.client_email, //I've also used my email here
serviceClient: key.client_id,
privateKey: privateKey,
accessToken: accessToken,
expires: expires,
},
});
var mailOptions = {
from: “me#here.com”
to: “me#there.com",
subject: "Ready",
text: “Really Ready"
}
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
return;
}
console.log("Message %s sent: %s", info.messageId, info.response);
});
});
which generated the error:
535-5.7.8 Username and Password not accepted.
But as I mentioned, I've tried differing configurations and settings and gotten just as many different errors...
SO... Has anyone had success in using service accounts for 2LO using nodemailer?
I'm using node 9.5.0 and nodemailer ^4.6.0
I got it working (2021!), these were the steps:
Log in to console.- https://console.cloud.google.com/
Create a service account under the project.
Click on the new service account, go to permissions and add a member. You will use this member's email address when sending the request.
Create keys for the service account. - keys -> add key. https://console.cloud.google.com/iam-admin/serviceaccounts
Download your key file. You will get something like service-account-name-accountid.json. It will have all the information you need to get the code below running.
Delegate authority to your service account https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority. Addhttps://mail.google.com/ as the scope.
Write some code like below:
const nodemailer = require('nodemailer');
const json = require('./service-account-name-accountid.json');
const sendEmail = async (email, subject, text) => {
try {
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
type: 'OAuth2',
user: email, //your permissioned service account member e-mail address
serviceClient: json.client_id,
privateKey: json.private_key
}
});
await transporter.verify();
await transporter.sendMail({
from: json.service_email,
to: email, //you can change this to any other e-mail address and it should work!
subject,
text
});
console.log('success!');
return {
status : 200
}
} catch (error) {
console.log(error);
return {
status : 500,
error
}
}
}
sendEmail('your_permissioned_service_account_email_address#some_place.com, 'testing 123', 'woohoo!');
Why? Because one the default scopes on your credentials for OAuth 2.0 client IDs are these:
email <- Can only view email address
profile
openid
If you want to send email using node mailer it should include this scope:
https://mail.google.com/
and which is a sensitive scope, so google needs to verify it first else you will receive some delegation error messages.
Follow this verification process.
And add scope in the consent page
Or
Make sure you're an admin of the gsuite then give your service account access to sending email or an admin can give your service account access to sending email.
This guide will help. It's in Japanese just translate it to english.
Old thread, but I've got this working just now (after a lot of trying) so a few suggestions for anyone interested:
Enable the Gmail API in the Cloud Console
Use your 'normal' email address as the user (not the Service Account email)
Go here https://admin.google.com/ac/owl/domainwidedelegation and add your service client to the list. Here you will have to type in your client_id for the Client Name part and https://mail.google.com/ as the API scope. This last part was hard to find, but made it work for me in the end.
Also, I found this guide very helpful: Here you will have to type in your client_id for the Client Name part and https://mail.google.com/ as the API scope before pressing the Authorise.

pass the credentials of user to all views node.js

I'm trying to build an android application using node.js web services,the first interface allow the user to connect to a host using ip address,login and password, so he can get all the databases,i want to save the object credentials to use in all other routes,i tried express-session but it didnt worked.
Any solution?
app.post('/connect',function(req,res){
sess=req.session;
sess.user=req.body.user;
sess.password=req.body.password;
sess.server=req.body.server;
sess.database=req.body.database;
console.log(sess)
user = req.body.user;
password = req.body.password;
server = req.body.server;
database = req.body.database;
var config = {
user: user,
password: password,
server: server,
database: database
};
// connect to your database
sql.connect(config, function (err) {
if (err) {res.json({success: false, message: "error connexion to SQL Server"});
sql.close()}
else{
res.json({success: true, message: "connexion established to SQL Server"});
sql.close();
}
});
});
In your case the request make by http lib of android (or another) which is not a browse then express-session will not work. Your server must be like a API server, client(android) request login server response a token (api key or the same), in next request client push data embeded token and server side can credentials the request. I suggest read about JWT (Json Web Token) to do this.
This is easy if you are using express module in node application.
You basically create routes using express and can pass the required data to the appropriate routes and views as follows
router.get('/', function(req, res, next) {
res.render('category',
{
videodata: vd
});
});
Here while rendering the response, the data that is to be passed is also included. It's name is videodata and value is vd

Can't send message to only one specific room through node.js and socket.io

I have a problem that i don't seems to be able to solve it. I'm doing some kind of integration with remote system and my code is in iframe but that can't be important for this one i hope :).
I'm trying to send a message from server to specific room/client to begin session. First thing I do is when user log in, I emit message from client side with username.
CLIENT.JS
conn.on('connect', function () {
conn.emit('session', { username: 'some_username' });
}, false);
And on server side i get message and join socket to the room.
SERVER.JS
socket.on('session', function(session) {
socket.join(session.username);
});
I have another module that communicates with this server.js script through redis. So i have two more events in server.js
SERVER.JS
var userCreate = redis.createClient();
userCreate.subscribe("userCreate", "userCreate");
var userDestroy = redis.createClient();
userDestroy.subscribe("userDestroy", "userDestroy");
userCreate.on("message", function(channel, data) {
socket.to(JSON.parse(data).username).emit('beginSession', data);
});
userDestroy.on("message", function(channel, data) {
socket.to(JSON.parse(data).username).emit('endSession', data);
socket.leave(JSON.parse(data).username);
});
But when ever i try to emit message from server to client i broadcast message to everyone. What am I doing wrong?
Well, from the syntax point of view you are doing everything correct.
Didn't you forget to specify the userId property in the endSession?
userDestroy.on("message", function(channel, data) {
socket.to(JSON.parse(data).userId).emit('endSession', data);
socket.leave(JSON.parse(data).userId);
});
If that doesn't work - you should provide the contents of a data object

Categories

Resources