How can I send an email to a person using Cloud Functions and Nodemailer?
On my app there's a contact screen where users can ask questions and send feedback to the app, and when the user presses a button, the Cloud Function gets triggered. However, I don't seem to recieve any emails whatsoever, I even checked the "Spam" folder.
What am I doing wrong?
My code for the Cloud Function looks like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const nodemailer = require('nodemailer');
admin.initializeApp(functions.config().firebase);
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'exampleemail#gmail.com',
pass: 'exampleemailpassword'
}
});
exports.sendEmail = functions.https.onRequest((request, response) => {
const { sender, phone, message } = request.query;
const mailOptions = {
from: sender.toLowerCase(),
to: 'exampleemail#gmail.com',
subject: 'New feedback email',
text: `${message} Phone: ${phone}`
};
// eslint-disable-next-line consistent-return
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
response.send(err.toString());
}
response.send('Email sent');
});
});
I see what you are doing wrong, you can't use gmail's SMTP transport service in server environments other than your own computer
Gmail has a limit of 500 recipients a day (a message with one To and
one Cc address counts as two messages since it has two recipients) for
#gmail.com addresses and 2000 for Google Apps customers, larger SMTP
providers usually offer about 200-300 recipients a day for free.
So I would recommend you to use a service like EmailJS to send emails
I was doing it wrong, I had to return a code to the HttpRequest in order to run the function property. Then, it works
exports.sendEmail = functions.https.onRequest((request, response) => {
cors(request, response, () => {
const { sender, phone, message } = request.query;
const mailOptions = {
from: sender.toLowerCase(),
to: 'exampleemail#gmail.com',
subject: 'New feedback email',
text: `${message} \nEmail: ${sender.toLowerCase()}\nPhone: ${phone}`
};
return transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return response.status(500).send({
data: {
status: 500,
message: error.toString()
}
});
}
return response.status(200).send({
data: {
status: 200,
message: 'sent'
}
});
});
});
});
Related
I have started a new email project. It's very challenging to me because first time I am working with own custom email project. I am using node.js for creating REST full API. Using imap-simple module for accessing Internet message access. Everything is working like send email, receive email, add flag etc from our own server.
But problem is when trying to move an email from Inbox to Drafts folder it's giving an error. Can you please see my code snippet below and guide me for the right way.
const imaps = require('imap-simple');
module.exports.moveEmail = async (req, res)=>{
let user = req.body;
let UID = req.params.uid
try{
const connection = await imaps.connect({
imap: {
user: user.user, // User email
password: user.password, // User email password
host: 'server.XXXX.com',
port: XXXX,
authTimeout: 10000,
tls: true,
tlsOptions: { rejectUnauthorized: false },
},
});
await connection.openBox('INBOX')
const searchCriteria = [['UID', UID], ['TO', user.user]]
const fetchOptions = {
bodies: ['HEADER', ''], // Empty string means full body
markSeen: false
}
const messages = await connection.search(searchCriteria, fetchOptions)
if (messages.length === 0) {
return res.send({message:`ID ${UID} Email not found`})
}
// console.log(messages)
connection.moveMessage(UID, 'Drafts', (err) => {
if (err){
console.log(err)
console.log({status:500, message:'Problem marking email move to Drafts'});
rej(err);
}else{
connection.end();
return res.send({status:200, message:`Email flag removed successfully!`})
}
})
}catch (error){
console.log(error)
}
}
Hope fully some one have a nice solution.
I've been trying to make an express middleware that sends an email using Nodemailer after the previous middleware finishes. I've come up with a few different designs, but ultimately each different version has it's drawback.
Ultimately, I would like the middleware to have a response from the previous middleware. If it is a success, then send a success email, otherwise, send an error email.
I came up with a dual design where one variation pushes to an error middleware, and a success leads to the next middleware. This contains some slight issues of sending multiple headers, specifically on an the second middleware erroring. I could say, if the mail errors out, do nothing. But that doesn't seem right. If anyone has any suggestions on a good design, that would be great.
From what you described, I would suggest not to create different middleware for that, but to just create one generic email function that would handle different type of messages. Then, just use that function in the first middleware and pass different parameters based on use case (success/error).
email-controller.js
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT,
secure: true,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
},
});
exports.send_email_message = (send_to, subject, message) => {
return new Promise((resolve, reject) => {
const email_message = {
from: { name: process.env.EMAIL_FRIENDLY_NAME },
to: send_to,
subject: subject,
text: message
};
transporter.sendMail(email_message).then(() => {
resolve(true);
}).catch((error) => {
reject(false);
});
})
}
custom-router.js
const { send_email_message } = require('./email-controller');
const express = require('express');
const router = express.Router();
router.get('/custom-middleware', async (req, res, next) => {
try {
// You can calculate "success" variable based on your custom logic
if(success){
await send_email_message('example#gmail.com', 'Success', 'This is body of success message.');
return res.status(200).json({ success: true });
} else {
await send_email_message('example#gmail.com', 'Error', 'This is body of error message.');
return res.status(400).json({ success: false });
}
} catch(error) {
return res.status(400).json({ success: false });
}
});
module.exports = router;
I was trying to send a test email using SMTP on node mailer but it says connection timed out. the snippet I was using is down below.
const nodemailer = require("nodemailer");
async function main() {
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
pool:true,
host: '213.55.96.132',
port: 25,
auth: {
user: "user#ethionet.et",
pass: "drafgthsjaid321##"
},
pool: true,
logger :true,
debug:true,
secure: false,
})
transporter.verify(function(error, success) {
if (error) {
console.log(error);
} else {
console.log('Server is ready to take our messages');
}
});
let mailOptions = {
from: "user#ethionet.et",
to: ["someemail#gmail.com",],
subject: 'Test email',
text: `Hello world`
};
transporter.sendMail(mailOptions, function(err, data) {
if (err) {
console.log("Error " + err);
} else {
console.log("Email sent successfully");
}
});
}
main().catch(console.error);
I don't mind leaking the credentials and it works when i try and send emails through SMTP from here.
why is this faliing?
You need to read a little more than the first page of documentation :)
Create your message
let message = {
...,
from: 'mailer#nodemailer.com', // listed in rfc822 message header
to: 'daemon#nodemailer.com', // listed in rfc822 message header
envelope: {
from: 'Daemon <deamon#nodemailer.com>', // used as MAIL FROM: address for SMTP
to: 'mailer#nodemailer.com, Mailer <mailer2#nodemailer.com>' // used as RCPT TO: address for SMTP
}
}
Send the message through the transporter
transporter.sendMail(...).then(info=>{
console.log('Preview URL: ' + nodemailer.getTestMessageUrl(info));
});
Turns out the problem was that my ISP blocks port 25.
pretty new to react only been doing it for a couple of weeks and I'm working on a project for personal use to send an email to my email using nodemailer which I have managed to do. the next part I want to do is add data to the email that will come from my MongoDB database like the order number, customer name and status of the job I've searched high and low on youtube and google and not really finding anything on the issue
also, it only runs when I type node server.js and then it automatically sends the email which I don't want I want it to run when submit is clicked when a status is updated in the database.
Here is the code for what I have on server.js
require('dotenv').config();
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: 'group2021#gmail.com',
to: 'edge#gmail.com',
subject: 'Project Update',
text: 'Hello {{name}} please find this email as an update to you project.'
};
transporter.sendMail(mailOptions, function(err, data) {
if(err) {
console.log('Error Occured!', err);
} else {
console.log('Email Sent!')
}
});
I'm not sure how your application looks like, I assume it's SPA react application.
I suggest you to create simple http server using Expressjs and creating endpoint which you will call from the client (react app) e.g. (the code is not tested is just an example)
const express = require('express');
const app = express();
const port = 3000;
const nodemailer = require('nodemailer');
app.get('/mail/:someID', async (req, res) => {
// someID is identifier to find data in db
// it will come from localhost:PORT/mail/>>someID<<
const { someID } = req.params;
let data;
try {
data = await mongoCol.FindOne({
/* query */
}); // reads data from mongo
} catch (err) {
return res.status(500).json(err);
}
// prepare content
var text =
'Hello {{name}} please find this email as an update to you project.\n' + data;
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: 'group2021#gmail.com',
to: 'edge#gmail.com',
subject: 'Project Update',
text: text
};
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
console.log('Error Occured!', err);
return res.status(500).json(err);
} else {
console.log('Email Sent!');
return res.sendStatus(200);
}
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
You should add some kind of authorization to not allow other people to send email by your server.
also, it only runs when I type node server.js and then it automatically sends the email which I don't want
This happens because your code is not in function and any time you import or start file (module) it will execute.
I am trying to create a simple REST API I can post an email to, to then email myself. I am using nodemailer and had set it up as an express app and it all worked fine confirming my authentication etc. is fine. I wanted to host it online so I have used claudia.js to create a lambda and API gateway setup but this seems to have broken it.
The Code
const nodemailer = require('nodemailer');
const secrets = require('./secret');
const apiBuilder = require('claudia-api-builder');
api = new apiBuilder();
module.exports = api;
var mailOptions;
var logMsg = "none";
api.post('/email', async (req, res) => {
mailOptions = {
from: secrets.email,
to: secrets.email,
subject: 'Email From: ' + req.body.senderEmail + ' | ' + req.body.subject,
text: req.body.content,
};
sendMail(mailOptions);
return logMsg;
})
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: secrets.email,
pass: secrets.pwd
}
});
function sendMail(mailOptions) {
logMsg="Starting Send Function";
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
logMsg = error;
return error;
} else {
logMsg = "Send Complete";
return true;
}
});
logMsg="Function finished";
}
When I debug via postman, by posting a raw JSON
{
"senderEmail": "test2",
"subject": "test",
"content":"test"
}
I receive "Function Finished" Which I dont really see how it is possible as surely the if or else should've fired under transporter.sendMail(..., returning from the function. I also don't receive an email which is my end goal
I had the same problem until I started returning the transporter
return transporter.sendMail(mailOptions)
.then(info => {
console.log('email sent: ', info)
return {'status': 'OK'}
})
.catch(err => {
console.log('email error: ', err)
return {'status': 'ERROR'}
})