NodeMailer is blocked on Azure App Service - azure

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

Related

Heroku Redis Add-On Error error:1408F10B:SSL routines:ssl3_get_record:wrong version number

After upgrading my Heroku Redis add-on to v6.2.3 from v4, Heroku papertrail logs display this error: Error accepting a client connection: error:1408F10B:SSL routines:ssl3_get_record:wrong version number I am connecting to Redis using NodeJs and the bull npm package (https://www.npmjs.com/package/bull). I found similar questions related to this error, along with Heroku documentation, and based on that I have set my bull redis options to the following:
redis: {
host: redisURL.hostname,
port: Number(redisURL.port),
password: redisURL.password,
tls: {
rejectUnauthorized: false,
},
},
Note the tls parameter. I have set it to Heroku's recommendations here: https://devcenter.heroku.com/articles/heroku-redis#connecting-in-node-js After getting stuck for a while, I attempted to simply comment out any client code that connects to Redis, delete the add-on, and re-provision the add-on. I expected to see no redis logs in papertrail when I did this, but I still see the same error, even when no code that connects to redis is being run... This leads me to believe maybe it's a setting on the actual Redis add-on instance, rather than an issue with my code, but I am at a loss.
Updates:
I logged into the redis:cli and did some investigation. client list reveals 2 client connections. 1 is the instance of the redis:cli I am running in my terminal, and another is the a client with a flag that means "the client is a replica node connection to this instance" (see https://redis.io/commands/client-list). What is interesting is the error that is being logged in papertrail shows the file descriptor for the client connection that is having the SSL error fd=12, while the 2 clients shown in client list have the file descriptors fd=10 and fd=11. So there must be another client connection with fd=12 that isn't appearing in client list command causing the error shown above.
Jasper Kennis' answer is correct. Adding tls: {rejectUnauthorized: false} fixed this issue for me. Unfortunately, Heroku only gives you a full REDIS_URL connection string, so you need to parse the password/host/port yourself (you can't specify both a URL and tls settings). Here's my BullModule.forRoot() config object if it helps:
redis: {
password: process.env.REDIS_URL.split('#')[0].split(':')[2],
host: process.env.REDIS_URL.split('#')[1].split(':')[0],
port: parseInt(process.env.REDIS_URL.split('#')[1].split(':')[1]),
tls: { rejectUnauthorized: false },
}
Using:
#nestjs/bull: 0.6.0,
Heroku redis: 6.2.3
Ran into the same problem. In addition to rejectUnauthorized: false, adding requestCert: true, solved it for me. In addition, some clients need agent: false, (but the version of Bull I'm using doesn't recognise that argument)
redis: {
host: redisURL.hostname,
port: Number(redisURL.port),
password: redisURL.password,
tls: {
rejectUnauthorized: false,
requestCert: true,
// agent: false, (not all clients accept this)
},
},

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.

How to catch email from local app server. Nodejs

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

NodeMailer : getaddrinfo Error

Looking for some insight into an error I'm getting.
on transporter.sendmail(func(err, info){}), the err variable returns this:
{ [Error: getaddrinfo ENOTFOUND smtp.gmail.com]
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'smtp.gmail.com' }
I don't see any error documentation for nodemailer on their site or github, and I haven't found anything useful on Google searches. The closest I see is this SO post. I am trying to send about 50 emails once a week through a cron job.
I have tried this with and without the nodemailer-smtp-pool package, and my transporter currently looks like this:
var transporter = nodemailer.createTransport(smtpPool({
service: 'gmail',
auth: {
user: 'xxx#gmail.com',
pass: 'xxx'
},
maxConnections: 5,
maxMessages: 200
}));
I am not using XOATH yet, because I'm not under the impression that I need to. I have removed the DisplayUnlockCaptcha for the gmail account I'm using, but I don't think that's related. For what it's worth, I'm using the MEAN stack for this app.
It looks like 'smtp.gmail.com' is not being found when nodemailer makes the getaddrinfo call, but I can't understand why.
Any insight is appreciated
edit:
from the developer of nodemailer:
ENOTFOUND means that the app was not able to resolve DNS A record for
smtp.gmail.com. Probably something wrong with your DNS server. This is
handled by Node and not by Nodemailer, there's nothing Nodemailer can
do if a hostname is not resolved. If this happens randomly then you
could edit your application to try again in a moment.
and it doesn't look like nodemailer supports proxies, or ever plans to. looks like a dead end to me.
I had the same error with my nodemailer setup and I fixed it by changing the gmail password to not include any special characters.
var transporter = nodemailer.createTransport(smtpPool({
service: 'gmail',
secure: false, // true for 465, false for other ports
auth: {
user: 'xxx#gmail.com',
pass: 'xxx'
},
maxConnections: 5,
maxMessages: 200
}));
Try this, It should work fine.

Resources