How to catch email from local app server. Nodejs - node.js

I have lite nodejs server. I am trying to implement password reset flow. I use nodemailer to send email with reset password link. I want to test if I send email properly. I don't want to use any remote smpt.
What I can use on my local environment to catch emails and check if they are good?

Try this command:
python -m smtpd -n -c DebuggingServer localhost:1025

I used mailcatcher. It is a super simple SMTP server which catches any message sent to it to display in a web interface.
I have following configuration:
let smtpConfig = {
host: '127.0.0.1',
port: 1025,
secure: false, // upgrade later with STARTTLS
auth: {
user: 'user',
pass: 'password'
}
};
Do not forget to add user and password in auth section. It can be even white space. But it can't be empty string in this case you'll get error.
const smtpTransport = nodemailer.createTransport(smtpConfig);
And now you can see all sent emails here http://127.0.0.1:1080

Related

NodeMailer is blocked on Azure App Service

I have a NestJS app deployed to a Windows Azure App Service. Like everything else in Azure, it works fine on my machine until I deploy it. Getting a 500 error. It looks like some kind of port restriction.
Error message:
DEBUG Creating transport: nodemailer (6.7.2; +https://nodemailer.com/; SMTP/6.7.2[client:6.7.2])
DEBUG Sending mail using SMTP/6.7.2 DEBUG [DJemKiOruKY]
Resolved localhost as 127.0.0.1 [cache hit]
ERROR [DJemKiOruKY] connect EACCES 127.0.0.1:587
DEBUG [DJemKiOruKY] Closing connection to the server using 'destroy'
Here's the code that configures the mailer. Our noreply email has a custom domain (noreply#our_company.com)
const transporter = nodemailer.createTransport({
host: 'smtp.office365.com',
port: 587,
secure: false,
requireTLS: true,
auth: {
user: process.env.NOREPLY_EMAIL_ADDRESS,
pass: process.env.NOREPLY_EMAIL_PASSWORD
},
logger: true
});
const info = await transporter.sendMail({
from: `Sender Name <${process.env.NOREPLY_EMAIL_ADDRESS}>`,
to: process.env.NOREPLY_EMAIL_RECIPIENT,
...
You have to specifically allow outbound traffic on port 587.
How you do this depends on your setup.
To verify that the port is open, go to the app service console:
tcpping smtp.office365.com:587

Connecting to azure flexible postgres server via node pg

I am using the free subscription at Azure and have successfully created a Ubuntu Server and a Flexible Postgres Database.
Until recently I accessed the DB directly from my Windows 10 desktop. Now I want to route all access through the Ubuntu Server.
For this I have installed Open SSH Client and Open SSH Server on my Windows 10 machine and done the necessary local port forwarding with ssh -L 12345:[DB IP]:5432 my_user#[Ubuntu IP]
The connection works, I confirmed it with pgcli on my desktop with pgcli -h 127.0.0.1 -p 12345 -u my_user -d my_db
But when I am trying to connect via node-pg I receive the following error
UnhandledPromiseRejectionWarning: error: no pg_hba.conf entry for host "[Ubuntu IP]", user "my_user", database "my_db", SSL off
I have already added a Firewall Rule in Azure with the [Ubuntu IP], and the error remains. What bugs me further is that in the Azure Portal of the DB I have enabled "Allow public access from any Azure service within Azure to this server", so the extra Firewall should not even be necessary for this connection.
For the last week, I have been stuck on this and now the connection is finally established, but not accessible by my code. Pretty frustrating. I would be glad about ANY pointers on how to fix this.
Edit #1:
I can't post the pg_hba.conf file. Because the Postgres DB is managed by Azure, I do not have access to pg_hba, which makes the situation more difficult to understand.
My node.js code for testing the connection:
const pg = require("pg");
const passwd = "...";
const client = new pg.Client({
user: 'admin',
host: '127.0.0.1',
database: 'test',
password: passwd,
port: 12345
});
client.connect()
client.on('uncaughtException', function (err) {
console.error(err.stack);
});
const query = "SELECT * FROM test";
try {client.query(query, (err,res) => {
if (err) {
console.error(err);
}
console.log(res);
})}
catch (e) {
console.error(e)
}
The comment by #jjanes helped me in understanding the issue, thank you.
This edited pg.Client config solved my problem:
const client = new pg.Client({
user: 'admin',
host: '127.0.0.1',
database: 'test',
password: passwd,
port: 12345,
ssl: {rejectUnauthorized: false}
});
I found this specific SSL option here https://node-postgres.com/features/ssl

Nodemailer cannot send email from within Docker container

I've been searching/reading/trying everywhere on the Internet for about 3 weeks before posting here ...
Context:
developing little website app
technologies:
Next JS (ReactJs, HTML, CSS) for both frontend and backend (Node)
Linux as host (Ubuntu 20.04 LTS)
Docker's container to encapsulate app (based on node:alpine image) (Docker version 20.10.6)
Nodemailer Node's module to send email
this is the code using Nodemailer to send the e-mail message:
import type { NextApiRequest, NextApiResponse } from "next";
import * as nodemailer from "nodemailer";
export default async (req: NextApiRequest, res: NextApiResponse) => {
res.statusCode = 200;
let transporter = nodemailer.createTransport({
host: process.env.NM_HOST,
port: parseInt(process.env.NM_PORT),
secure: true,
auth: {
user: process.env.NM_USER,
pass: process.env.NM_PASS,
},
tls: {
rejectUnauthorized: false,
},
});
// console.log("User:");
// console.log(process.env.NM_USER);
let info = await transporter.sendMail({
from: "Website <xxx#xxx.com>",
to: "Website <xxx#xxx.com>",
subject: "New contact",
text: "NAME:\n" + req.body.data.name + "\n----------\nEMAIL:\n" + req.body.data.email + "\n----------\nBODY:\n" + req.body.data.body,
}, function (err, info) {
if (err) {
console.log(err)
} else {
console.log(info);
}
});
console.log("Message sent: %s", info);
res.json({
a: req.body.data.name,
b: req.body.data.email,
c: req.body.data.body,
});
};
Issue:
when I try to send e-mail using Nodemailer launching my app from Linux host as "npm run start" or "npm run dev", mails get delivered
when I try to send e-mail using Nodemailer launching my app from Docker's container, i get following error (from app's output itself)
Error: connect ECONNREFUSED 127.0.0.1:465
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1133:16) {
errno: -111,
code: 'ESOCKET',
syscall: 'connect',
address: '127.0.0.1',
port: 465,
command: 'CONN'
}
What I already tried and what I observed:
ping google.com (and many others) works from within container (using docker exec -ti container-name sh command)
starting container with docker run --dns 8.8.8.8 ... -> same result (error above)
container's and host' /etc/resolv.conf are different (but I think that this might not be the point, as ping command correctly resolves, but feel free to say me wrong if I am)
I am not a sys admin (i am a developer), so I don't know if iptables or ufw (firewall) may be implied in this thing (btw, it's difficult to install non pre-installed packages on node:alpine)
Email server authentication is correct (both username, hostname, password) as it works correctly when i launch my app as npm run start or npm run dev
switch container's network between bridge (default) bridge (custom with docker-compose) and host ... same issue (error above)
Anyone willing to help is really appreciated.
Found out what wasn't working: I was using docker-compose WITHOUT --env-file option.
That way all the environment variables (e.g. PORT, HOST, PSWD, USR) I was trying to access within my app, were left undefined (this was because those environment variables weren't already built in during the building step - design choice, but rather accessed at runtime with process.env)
SOLUTION (change .env file part as suits your situation):
docker-compose --env-file ./.env.production
Useful official resource (docker-compose)
Docker-compose using --env-file option

Cannot connect to AWS SES SMTP endpoint

I'm building an application that will use AWS SES to send email via SMTP. I've properly configured a domain and confirmed I can send email from that domain using the AWS SDK. I've created SMTP credentials and ensured the IAM user is properly configured with the right permissions. I've written a test script that uses Nodemailer to send the email.
The test script runs successfully using my personal development machine on my home network, but the script will NOT work when using the development laptop issued by my corporate client on my home network. The corporate laptop runs many security tools, including ZScaler. I also know that, due to the ZScaler service, NPM must be set to use a self-signed certificate (the command is npm config set cafile {CA_FILEPATH}).
I don't know why the script won't work on the corporate laptop, and I would appreciate some help in figuring what to try next.
Here's the script:
'use strict';
const nodemailer = require('nodemailer');
const runtest = async function() {
console.debug('Creating the SMTP transport');
const transporter = nodemailer.createTransport({
host: 'email-smtp.us-west-2.amazonaws.com',
port: 465,
secure: true,
auth: {
user: 'myusername',
pass: 'mypassword',
},
});
console.debug('Building mail options');
const mailOptions = {
from: 'me#example.com',
to: 'you#example.com',
subject: 'subject',
text: 'body',
html: '<h1>Hi</h1',
};
console.debug('Sending mail...');
const info = await transporter.sendMail(mailOptions);
console.debug(`Sent mail. Info: ${JSON.stringify(info, null, 2)}`);
console.info('Message sent!');
};
runtest().catch(console.error);
Here's the result when run from the corporate laptop:
Creating the SMTP transport
Building mail options
Sending mail...
Error: read ECONNRESET
at TLSWrap.onStreamRead (internal/stream_base_commons.js:200:27) {
errno: 'ECONNRESET',
code: 'ESOCKET',
syscall: 'read',
command: 'CONN'
}
Things I've tried:
Playing with TLS settings such as rejectUnauthorized: false and specifying the TLS version
Connecting to or disconnecting from the corporate VPN
I found a reference on this Github issue that suggested testing the connection with openssl. I ran this command openssl s_client -connect email-smtp.us-west-2.amazonaws.com:465, and this was the result (seems ok):
CONNECTED(0000021C)
write:errno=10054
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 336 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
In my case, it was the node version that caused this error. I have upgraded my node version to v12.x to fix the issue.

Mail sends from localhost but not from live site on digital ocean

I am using the Sendgrid API to send emails from my Node.js project. When running on my local machine this works just fine but now I have deployed to Digital Ocean (Ubuntu) the mails do not send. I have read that Digital Ocean blocks smtp ports by default and you can apparently open them through the command line but I can't find an easy to understand explanation on how to do this.
const nodemailer = require("nodemailer");
const sendgridTransport = require('nodemailer-sendgrid-transport');
const transporter = nodemailer.createTransport(sendgridTransport({
auth: {
api_key: process.env.SENDGRID_API
}
}));
return transporter.sendMail({
to: 'info#example.com',
from: email,
subject: subject,
html: `<h1>Contact Form</h1>
<p>Name: ${name}</p>
<p>Email: ${email}</p>
<p>${comments}</p>
`
});
UPDATE
If I remove the .env for the api key and actually hardcode it in eg:
const transporter = nodemailer.createTransport(sendgridTransport({
auth: {
api_key: '12345677788999'
}
}));
then my emails send. This is my .env file ( I am using dotenv)
DB_USER=username
DB_PASSWORD=password
DB_NAME=mydbname
SENDGRID_API=12345677788999
So, not sure why that would be?
Have you exported this "SENDGRID_API" in the environment. Then only you can use process.env.SomeEnvironmentVar.
If you are using PM2. You will have to add it to the ecosystem file. Then it will use that config and boot your application. Making all the vars available.
I had the same issue using SendGrid, Digitalocean (Ubuntu) and PM2.
It seems that PM2 doesn't automatically detect changes in .env file as #himank mentioned in his answer, so i had to delete the project from PM2, then started it again.
Kindly note:
I followed this guide to set global Environment variables:
https://www.serverlab.ca/tutorials/linux/administration-linux/how-to-set-environment-variables-in-linux/
I also followed this guide to configure PM2 with my Nodejs (Nestjs) project:
https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-20-04

Resources