How to build local node.js mail server - javascript

I have spent couple of days implementing my own mail server using node.js. I used modules like "smtp-server" for creating smtp server and also "smtp-connection" to connect and send mail to it. But I'm getting confused because I don't know how to send mails from my smtp server to providers smtp servers like google or yahoo.
Can anyone help me?
Here is my code for more information:
My index.js file:
var SMTPServer = require('smtp-server').SMTPServer;
var port = 9025;
var serverOptions = {
name: "smtp-interceptor",
onConnect: onConnect,
onAuth: onAuth,
onData: onData
};
var server = new SMTPServer(serverOptions);
server.listen(port, 'localhost', function () {
console.log('SMTP server is listening on port ' + port);
});
function onConnect(session, callback) {
console.log('Connected');
return callback(); // Accept the connection
}
function onData(stream, session, callback) {
stream.pipe(process.stdout); // print message to console
console.log('Session \n', session.envelope);
stream.on('end', callback);
}
function onAuth(auth, session, callback){
if(auth.username !== 'Mahan' || auth.password !== 'Tafreshi') {
return callback(new Error('Invalid username or password'));
}
callback(null, {user: 123}); // where 123 is the user id or similar property
}
And my connection.js file:
var SMTPConnection = require('smtp-connection');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var connection = new SMTPConnection({
host: 'localhost',
port: 9025,
secure: false
});
connection.connect(function (){
console.log('Connceted to SMTP server');
var auth = {
user: 'Mahan',
pass: 'Tafreshi'
};
connection.login(auth, function (err) {
if(err)
return console.log('Login Failed \n', err);
console.log('Login Successful');
var envelope = {
from: "testapp#testapplocal.com",
to: "mahantp19#gmail.com"
};
var message = 'Test message1';
connection.send(envelope, message, function (err, info) {
if(err)
return console.log('Error : ' + err);
console.log('Message sent');
console.log('Accepted : ' + info.accepted);
console.log('Rejected : ' + info.rejected);
console.log(info.response);
connection.quit();
console.log('Quit connection');
connection.close();
});
});
});

There are many checks an email must pass before it's accepted by most mail providers. These checks attempt to validate the server sending the message is authorized to send on behalf of the sender.
IE: My server can send an email saying it's from "someone-special#somewhere-important.com"... That doesn't mean I'm "anywhere important" by any means.
While you may have had success sending mail from an SMTP server in the past using another technology such as PHP or an Exchange Server, the rules have changed significantly. Gmail has just began full enforcement this year.
I would assume your current issue has nothing to do with node as much as recent changes by the big providers.
Some of the checks that are needed include:
DKIM Keys (DNS Record)
SPF Record (DNS Record)
DMARK has been setup.
Dedicated IP Address for the server is required.
Your servers IP not being blacklisted.
The content of your email passes their filters.
Attempt to have an email sent from your server appear to be from a visitor or customer.
Among many others.
Any domain you want to "Act as Sender" must have these in place for most of the major providers to accept you message.
Google has a great set of tools and walkthroughs on getting an IP/Domain setup.
Visit the Google MX Record Checker and enter in the domain/subdomain you want to use as sender and it will tell you everything that is failing as well as passing.
Alternative Solutions
I use sendgrid.com. They have A node library that makes sending mail very easy. They also provide me the ability to proxy messages via SMTP. This means you can utilize the standard methods to deliver messages. You will just change out "localhost" with an hostname they provide. However, if this is for a new setup, go for the API.
Whomever is hosting your email should offer the ability for you send messages via SMTP or an API
An endless supply of other providers are out their, most of which allow low volume senders to send for FREE.
Word of warning
I tried for a few years keeping up with all the changes and inevitably, I continued to hit barriers of blocked messages with no ability to know until someone did not get an email. If your sending low volume, you should be able to use third parties without paying paying for it. If you are sending high volume, the cost of their service is cheap compared to the endless issues you will encounter even once you get it initially rolling.
PS. I have no affiliation with any email provider or sender. I pay them too.

Related

Twilio function writing to aws rds postgres error

I wrote the below twilio function to store incoming messages into a postgres database in RDS on AWS. I'm getting a 504 timeout error. Details of how I am running:
I'm running this by deploying the function to twilio & adding it as a widget to a twilio studio flow.
My postgres database is in RDS. It is publicly accessible and I'm able to access it from my local machine (I added a security rule for My IP. I'm not sure if I need to add a rule for Twilio, I could find a specific IP they would be on.)
This is my personal computer, so it shouldn't have any extra firewalls. Any thoughts would be appreciated!
I'm not sure if:
There is something wrong with the below script or
AWS/RDS database is refusing connection. I don't know how to properly update my security rules to allow traffic from twilio.
const{Client} = require("pg");
exports.handler = async function(context, event, callback) {
console.log("HELLO")
// Not sure what the below does
// context.callbackWaitsForEmptyEventLoop = false;
// Add database config
const client = new Client({
host: context.host,
port: context.port,
user: context.user,
password: context.password,
database: context.database
});
// Try actually connecting to the database
try {
await client.connect();
console.log("connected successfully");
const user = ["12222222222", "2022-07-10T00:22:10Z", '{"question1": {"question": "How are you?", "answer": "great"}}'];
// Try to actually store the data
await client.query("INSERT INTO text_responses (phone_number, datetime, response) VALUES ($1, $2, $3::jsonb)", user);
await client.end();
console.log("Executed!");
callback(null, "12222222222");
} catch (e) {
console.log(`error: ${e}`);
callback(e);
}
};
Twilio error
Outbound HTTP Request Failed: Request URL: https://example-2039-dev.twil.io/log-sms-db
Request Method: POST
Response Status Code: 502
Response Content Type:
Error - 81016
Outgoing HTTP request failed
The outgoing HTTP request from a Studio widget failed.
Possible Causes
The URL you are requesting is incorrect
The response is badly formed
The URL returned a 4xx or 5xx error code
Possible Solutions
Make sure the request results in a response code 2xx or 3xx

Nodemailer connection timeout error

I am using nodemailer module to send mail from my nodejs application.
I am getting Error: connect ETIMEDOUT xxx.xxx.xx.xxx:465. Can any one help me in solving this.
Here I am pasting my code.
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'my_mail_id#gmail.com',
pass: 'my_gmail_password'
}
});
console.log('created');
transporter.sendMail({
from: 'my_mail_id#gmail.com',
to: 'my_mail_id#gmail.com',
subject: 'hello world!',
text: 'hello world!'
});
This may be firewall problem. I faced similar problem in Ubuntu (Digital Ocean server). Tried to fix the issue for 3 days, tried using auth2 also, tried with inactive firewall using ufw inactive command, but no luck. Finally I checked Digital Ocean admin panel and created firewall for the droplet. Problem solved by enabling TCP inbound and outbound in firewall settings.
Have you looked at this answer.
It turns out that in order for Google to authorize a third party server to access your account via SMTP now, you have to enable “Less Secure Apps” on your gmail account, if you want to use username/password (more info here).
So you have two option:
use OAuth
make your account less secure
// Create a SMTP transport object
var transport = nodemailer.createTransport("SMTP", {
service: 'Hotmail',
auth: {
user: "username",
pass: "paasweord"
}
});
console.log('SMTP Configured');
// Message object
var message = {
// sender info
from: 'abc#hotmail.com',
// Comma separated list of recipients
to: req.query.to //'aadityashukla9#hotmail.com',
// Subject of the message
subject:req.query.subject //'Nodemailer is unicode friendly ✔',
// plaintext body
text: req.query.text //'Hello to myself!',
// HTML body
/* html:'<p><b>Hello</b> to myself <img src="cid:note#node"/></p>'+
'<p>Here\'s a nyan cat for you as an embedded attachment:<br/></p>'*/
};
console.log('Sending Mail');
transport.sendMail(message, function(error){
if(error){
console.log('Error occured');
console.log(error.message);
return;
}
console.log('Message sent successfully!');
//transport.close(); // close the connection pool
});
I experienced this same issue today, found this documentation...
https://nodemailer.com/usage/using-gmail/
Had to do a capcha process from the server, by visiting a url while logged into gmail.
Hopefully it helps others.
There are the only reasons of this error:
Less Secure Apps: you have to Enable the "Less Secure Apps" from your Gmail account.
Use OAuth
Besides the already mentioned reference to the information at https://nodemailer.com/usage/using-gmail/, in my case the Internet Router (Speedport W724V) was still a problem. This keeps a list of all allowed SMTP servers. After I had extended the list accordingly, it worked perfectly. I had to do the same with smtp.ethereal.email.
I'm not sure if should be posting this answer but I've faced the same problem while using GMAIL and the reason behind the error for me was being connected to a vpn. I disabled it and now it works.
I'm using an application password
open port inbound outbound rule 587 or others, whichever you are using on server aws/google etc.
host: host,
secureConnection: false,
port: 465,
secure: true,
auth: {
user: user,
pass: pass
}

send body form to gmail via node.js

I'm trying few days to composing mail sending with node.js to gmail with no success :-(
at the beginning of tries I try to send form submittion to my gmail but first I need to understand how do I sent simple mail from body to gmail,
perhaps I wrong with syntax or missing something?
actually I uses "heroku" as storage and domain for my site
I tried several plugins (such as mailgun, send grid and more) but the process was too complicated integrate their API's into my site.
actually,
I find this article in stack overflow that describe how to send the via nodemailer in relation to my error - URL: node.js nodemailer gmail error
when i copy the answer1 to my code i still receiving error.
I' also pass trough all gmail setup how to turn off security block for less secured apps but i'm still receiving error.
all the requires installed over my npm
npm install --save
** code **
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
function handleSayHello(req, res) {
var transport = nodemailer.createTransport(smtpTransport({
service: 'gmail',
auth: {
user: 'myGmail#gmail.com', // my mail
pass: 'myPassword'
}
}));
var mailOptions = {
from: 'myGmail#gmail.com', // sender address
to: 'myGmail#gmail.com', // list of receivers
subject: 'Email Example' // Subject line
//text: text //, // plaintext body
//html: '<b>Hello world ?</b>' // You can choose to send an HTML body instead
};
transport.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
res.json({
yo: 'error',
err: error
});
} else {
console.log('Message sent: ' + info.response);
res.json({
yo: info.response,
info: info
});
};
});
}
router.get('/', function (req, res, next) {
handleSayHello(req, res);
});
then i receive this error:
{
"yo": "error",
"err": {
"code": "EAUTH",
"response": "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbtx\n534-5.7.14 e8jnXXDaDg-dpFfc3H5ljeaBdmnxbXBDXMh-aXS-mmV4gQsXMSZLiiJHDXuOr3wy-IR2Zp\n534-5.7.14 xnznWLf5y5e3xTbJNlZBNcxBMajM9-SFQGy1MQM2XZRpHgtywuDtEj5iPiP0b2T6Wjbsxg\n534-5.7.14 hgehfzufG6h13qhjQK5IgRPNQsSICRQBtRCl3E1J62wFo8bnvZv4peY5aK55JMpwhSavJb\n534-5.7.14 ho-b9ExGGsXFmw_Er6lc8m3vCmO_Q> Please log in via your web browser and\n534-5.7.14 then try again.\n534-5.7.14 Learn more at\n534 5.7.14 https://support.google.com/mail/answer/78754 t35sm887733qtc.40 - gsmtp",
"responseCode": 534,
"command": "AUTH PLAIN"
}
}
if someone can take my code and fix it (if needed) and explain simply what do i need to modify in my google account I'll be great-full so much!
to allow from google/gmail, you should follow these links and allow to less secure apps access:
unlock account
and
Less secure apps
Let me know if still have issue, I'll check/debug your code.

Socket.io - Implementing a user-socket association map for private messaging

I'm trying to create a private messaging system using socket.io
In order to associate the users with their sockets, most sites are suggesting something like this:
var people = {};
client.on('connection', function(socket) {
//join the server
socket.on('add user', function(user_id) {
//create user-socket map
people[user_id] = socket.id;
});
});
In my opinion, the problem with the above code is that the user_id is sent from the client side, so if the user somehow modify it and send another user_id an impersonation will take place.
Also, I can't access req.user._id under client.on('connection'... so how am I supposed to get the user_id from the server's side? I'm using node.js, passport and express.
I would use jsonwebtoken and socketio-jwt modules for solving this security issue.
Server:
var secret = 'shhhhhh';
app.get('/getJWT', function(req, res) {
/* Do your authentication here using header and get the userId */
var userId = 'someId';
var jwt = require('jsonwebtoken');
var token = jwt.sign({ 'userId': userId }, secret);
res.json({
token: token
});
});
var socketioJwt = require('socketio-jwt');
io.use(socketioJwt.authorize({
secret: secret,
handshake: true
}));
io.sockets.on('connection', function (socket) {
var userId = socket.decoded_token.userId;
/* your logic */
Client:
var token = "token you got from the /getJWT"
var c = io.connect('http://localhost:3000/', { query: "token=" + token });
As the token is encoded with a secret, client cannot change and send it.
Refer this article to know why this is better.
You're missing the most important part... Your code has to verify the usr is who he says he is. Plain and simple. I've done this multiple ways:
If users are logging in via PHP code, I move the session data to a mysql database. I then use a string on the PHP side to generate a response for a challenge to the client, who sends it to my web socket server. The WS server will challenge the client and look up the session information in the mysqldb. Done.
In my more recent developments, the actual login process is done via the web socket server. I verify the user credentials via whatever DB (in my instance, MySQL) and tie the username to the socket. Finished...
Do not purely rely on the javascript-based site to say "My name is." Otherwise, as you said, user impersonation becomes a walk in the park. You MUST validate that the user is who he says he is IF you're implementing a system where that matters. "Web sockets" themselves are not magical components that do this for you.
var people will be accessible on the same process.
When you want to scale with multiple socket server and balancing between them, then this idea for keeping people object locally will be not helpful.
Create authenticate event for authentication and set socket.userId and socket.isAuthenticate = true flag. In other events if socket.isAuthenticate is false, kick them out.
Make use of 'socket.io-redis' adpater for communication among many socket.io server. ( So when user1 from server1 send message to user2 which is in server2, will work ).
For socket - user association with multiple process, you can join Room with their userId, on authentication, join room like socket.join('myuserId');
and when to send message to that user, you can use io.to('myuserId').emit('message', "Hi How are you?"):
you can Send additional data on socket connection like this:
client side :
var c = io.connect('http://localhost:3000/', { query: "userId=value01" });
server side :
// extract userId param from connected url
io.on('connection', function(socket) {
var socket_param_userId = socket.handshake['query']['userId'];
console.log(socket_param_userId); //show value01
});

node_mailer doesn't return err but email not sent

I can't quite figure this out one... I have a SMTP server that's hosted on the same network as me, I can ping it and attempt to send emails, but the actual email never comes through. I'm using node_mailer... During the callback no error is returned... There is no authentication on the server as it's only used internally, and I'm not sure if that's maybe part of the problem. It works via ASP, but I'd like to get it working with Node.js
My script is basically just this:
email.send({
host : "theaddressoftheserver(can ping)",
port : "25",
domain : "theaddressoftheserver(can ping)",
to : "Some#internalEmail.com",
from : "Some#internalEmail.com",
subject : "Test",
body: "Test"
},
function(err, result){
if(err) console.log(err);
else console.log("Appears to have sent...");
});
I would recommend you to use Postmark.
Postmark helps small and large web applications deliver and track transactional email. Stop worrying about setup, delivery, and server maintenance. We already excel at this.
There are already two Postmark libraries for Node.js.
Postmark.js by Chris Williams
node-postmark by David Pitman
Example
var postmark = require("postmark")("YOURAPIKEY");
postmark.send({
"From": "donotreply#example.com",
"To": "target#example.us",
"Subject": "Test",
"TextBody": "Test Message"
});
I recently answered a similar question, it might help you:
https://stackoverflow.com/a/12623787/340736
Unfortunately, it's kind of hard to know exactly where your problem lies. Is the ASP-script on the same server? Have you tried running telnet against the server and sending it manually? Do the Node process have firewall restrictions?
One thing that comes to mind is that if you say that your ASP-script works, and that your SMTP-server uses no authentication. But could it be that is is, and that it is impersonating your user (the user in which the ASP-process is running under) and authenticating with that (AD authentication)..
Just a wild guess.
I figured node_mailer to send emails from a gmail account. I used code,
const transporter = createTransport({
service: gmail,
auth: {
user: process.env.MAILADDRESS,
pass: process.env.MAILPASSWORD
}
});
let mailOptions = {
from: process.env.MAILADDRESS,
to: recipient#email.com,
subject: 'verification code for verify email',
text: 'verification code
}
transporter.sendMail(mailOptions, function(err, info){
if (err) {
// something
} else {
// something
}
})
This is simple. In order to make this work I had to make sure Gmail account's Less secure app access on before using that email. I'm talking about the email that I user to send email. (Sender's email).
So my point is if there is any security option in your SMTP server that's hosted on your same network, you need to turn it off in order to node_mailer to use email address.

Categories