There is a scenario where I need to send event meeting invites to end users. I am able to generate the ICS file and send it as attachment. But the ICS files are not readable or added in User Calander.
Code to generate and send email is as below:
var transport = require('nodemailer-smtp-transport'),
transporter = nodemailer.createTransport(transport(config.mailer)),
sendMail = function(mailOptions) {
transporter.sendMail(mailOptions, function(err, response) {
if (err) return err;
return response;
});
},
eventEmailToUser = function(user, events, createdBy, mailOptions) {
var ical = require('ical-generator');
var cal = ical();
var username = user.username ? user.username : ' ';
var eventName = events.title ? events.title : ' ';
var eventDate = moment.tz(events.date, 'Asia/Kolkata');
eventDate = eventDate.format('YYYY-MM-DD h:mm a');
cal.addEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: events.title,
uid: events._id, // Some unique identifier
sequence: 0,
description: events.description,
location: events.location,
organizer: {
name: createdBy.username,
email: createdBy.email
},
method: 'request'
});
var path = '/files/' + events._id + '.ics';
cal.save(path, function(err, file) {
if (err) return err;
});
mailOptions.alternatives = [{
contentType: "text/calendar",
contents: new Buffer(cal).toString()
}];
mailOptions.attachments = [{
filename: events.title + '.ics',
filePath: path
}];
mailOptions.html = [
'<div>',
'<div>Hi <b>' + username + '</b><br/<br/>',
' You have just confirmed to attend <b>' + eventName + '</b> on <b>' + eventDate + '</b>',
' <br/><br/>',
'Thanks',
' <br/>',
'</div>',
'<br/>',
'</div>'
].join('\n\n');
mailOptions.subject = 'Invitation for' + eventName;
return mailOptions;
};
exports.sendInvite = function(req, res) {
var userMailOptions = {
to: 'abc#gmail.com',
from: 'xyz#gmail.com',
};
userMailOptions = eventEmailToUser(user, events, eventCreator, userMailOptions);
var userEmailresult = sendMail(userMailOptions);
};
The first issue that strikes me is that you are missing an ATTENDEE property which is required in any iMIP REQUEST.
There might be other issues but we would need to see your full MIME message instead of your code to really spot those. As a starter, you might want to doublecheck Multipart email with text and calendar: Outlook doesn't recognize ics
Related
I am building an IOT application which connects to an MQTT server where users subscribe to a topic for a particular building. I am able to connect, retrieve the information I need, and save it to a database.
The problem is, each individual user is stored in the session, and the connection parameters are submitted in a form, thereby the Subscribe function, which is needed for the topic subscription loses the information it needs for connection on each server restart.
What is the proper way to setup a cron task, which stores the submitted info for each user, along with their session, when the server is restarted(especially when it crashes from a bug)?
var mqtt = require('mqtt');
var Building = require('../models/Building')
var Volume= require('../models/Volume')
/////////////////////////////////////////////////////////////////////////
var today = new Date();
var date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
///////////////////////START MQTT SUBSCRIPTION//////////////////////////////////////////////////////////////////
const Subscribe = async (req, res, name) => {
const options = {
port: port,
username: req.body.username,
password: req.body.password,
clientId: "someclientid"
}
const client = mqtt.connect("someserver", options);
var topic_list = "sometopic"
client.on('connect', function () {
client.subscribe(topic_list, function (err, granted) {
if (err) {
console.error(err);
return;
}
console.log('Subscribed to topic: ' + topic_list);
});
console.log("connected flag " + client.connected);
})
client.on('message', function (topic, message, packet) {
var msgObject = JSON.parse(message.toString())
var data = JSON.stringify(msgObject.data).slice(-9, -5);
console.log(JSON.stringify(msgObject.data))
var v = new DataView(new ArrayBuffer(4))
v.setUint32(0, `0x${data}0000`)
console.log('message is ' + v.getFloat32(0))
var decimal = v.getFloat32(0);
storedata(req, decimal, name);
});
}
/////////////////////////End MQTT SUBSCRIPTION//////////////////////////////////////////////
async function storedata(req, value, name) {
const absvalue = Math.abs(value)
if (absvalue != 0) {
var building = await Building.findOne({
user: req.user,
name: name
});
if (building) {
const oldvolume = await Volume.create({source:name, calculated_at:date, volume:absvalue, user:req.user});
oldvolume.save()
console.log(oldvolume)
}
}
}
module.exports.Subscribe = Subscribe;
Dear All: I am sure many of you have discussed above topic multiple times after I am going through all the example and references I have managed to write the code to reply to same email ThreadID. But Unfortunately while I am responding to same ThreadID emails it's going as new email. I have attached my complete NodeJS Code help me to review and let me know where should I have to make the changes.
const {google} = require('googleapis');
const mailComposer = require('nodemailer/lib/mail-composer');
var program_name = process.argv[0]; //value will be "node"
var script_path = process.argv[1]; //value will be "yourscript.js"
var Sender_Email = process.argv[2]; //value will be "Sender Email"
var Receiver_Email = process.argv[3]; //value will be "Email To"
//var CC_Email = process.argv[4]; //value will be "Email Cc"
var Email_Subject = process.argv[4]; //value will be "Email Subject"
var Email_Template = process.argv[5]; //value will be "Email Template"
var ThreadID = process.argv[6]; //Path to attach the file
var Dec_Message_ID = process.argv[7]; //Encoded messageid
var FileAttachment = process.argv[8]; //Path to attach the file
var dateFormat = require('dateformat');
var day=dateFormat(new Date(), "mmm dd, yyyy HH:MM tt");
class CreateMail{
constructor(auth, to, cc, sub, body, task, attachmentSrc = [FileAttachment]){
this.me = Sender_Email;
this.task = task;
this.auth = auth;
this.to = Receiver_Email;
//this.cc = CC_Email;
this.sub = Email_Subject;
var fs = require('fs');
this.body = fs.readFileSync(Email_Template,{encoding:'utf-8'});
this.gmail = google.gmail({version: 'v1', auth});
this.attachment = attachmentSrc;
}
//Creates the mail body and encodes it to base64 format.
makeBody(){
if(this.attachment.length>0){
var arr = [];
for(var i=0;i<this.attachment.length;i++){
arr[i] = {
path: this.attachment[i],
encoding: 'base64'
}
}
}
let mail;
//Mail Body is created.
if(this.attachment.length>0){
mail = new mailComposer({
from: "Arthanareeswaran Chandrasekaran <arthaaadhi#visha.page>",
//sender: this.me,
to: this.to,
//cc: this.cc,
replyTo: this.to,
inReplyTo: "<CAO29sXBTxmE8M=xyTkdFfsrxB_Mdr5e6N6vXiijwTY9rn1kzpQ#mail.gmail.com>",
references: "<CAF7UyHwMrUvy-ZLNyRfjDmX876EKi5T-oc8E_tXy2PwO19dZ_Q#mail.gmail.com> <CAO29sXBH_B0yG4G2p6tdW1uk_tq9qFXmc01CPO5HJopkvMbU4Q#mail.gmail.com> <CAO29sXCcHv4LQSumjht_5zHEYvSzjfYkGr+yCEHfjwnqRvt0=Q#mail.gmail.com> <CAO29sXCPAxzWG0dC-TKEi4cR3xM8hbHhSJQ0ZAhbXBjsp503oA#mail.gmail.com> <CAO29sXA2mpqx6qbEeB5ke_6kUTrwXsqMD8ku0Aq3E_R07YzCLg#mail.gmail.com> <CAO29sXBTxmE8M=xyTkdFfsrxB_Mdr5e6N6vXiijwTY9rn1kzpQ#mail.gmail.com>",
subject: this.sub,
html: this.body,
textEncoding: "base64",
attachments: arr
});
}
else{
mail = new mailComposer({
to: this.to,
cc: this.cc,
html: this.body,
subject: this.sub,
textEncoding: "base64"
});
}
//Compiles and encodes the mail.
mail.compile().build((err, msg) => {
if (err){
return console.log('Error compiling email ' + error);
}
const encodedMessage = Buffer.from(msg)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
if(this.task === 'mail'){
this.sendMail(encodedMessage);
}
else{
this.saveDraft(encodedMessage);
}
});
}
//Send the message to specified receiver.
sendMail(encodedMessage){
this.gmail.users.messages.send({
userId: this.me,
resource: {
raw: encodedMessage,
threadId: ThreadID
}
}, (err, result) => {
if(err){
return console.log('GMail API - The API returned an error: ' + err);
}
console.log("GMail API Sending Email Reply from server:", result.data);
});
}
//Saves the draft.
saveDraft(encodedMessage){
this.gmail.users.drafts.create({
'userId': this.me,
'resource': {
'message': {
'raw': encodedMessage,
threadId: ThreadID
}
}
})
}
//Deletes the draft.
deleteDraft(id){
this.attachment.gmail.users.drafts.delete({
id: id,
userId: this.me
});
}
}
module.exports = CreateMail;
Thanks for your help...
I suggest you update your code to this and check that the References, In-Reply-To and Subjects headers match:
function replyToMessage(auth) {
const gmail = google.gmail({
version: 'v1',
auth
});
const messages = [
'From: NAME <email#email.com>',
'To: NAME <email#email.com>',
'References: <REFERENCE1> <REFERENCE2>',
'In-Reply-To: <IN_REPLY_TO>',
'Content-Type: text/html; charset=utf-8',
'MIME-Version: 1.0',
'Subject: Re: SUBJECT',
'',
'BODY_OF_THE_REPLY',
'',
];
const message = messages.join('\n');
const encodedMessage = Buffer.from(message)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
gmail.users.messages.send({
auth: auth,
userId: 'me',
resource: {
raw: encodedMessage,
threadId: 'THREAD_ID'
}
});
}
Also please bear in mind that in order to see the replies accordingly, you will have to turn on the Conversation View from Gmail Settings.
According to the documentation:
You can choose whether replies to emails are grouped in conversations, or if each email shows up in your inbox separately.
Hence, if this setting is not turned on, the email will show up separately in your inbox.
Reference
Gmail Help.
As part of small email CRM project, i have created a Nodejs app. While i send email through gmail send api, the messages are not grouped.
const sendObject = {}
output.data.messages.map(each => {
sendObject.threadId = each.threadId // ThreadID is unique.
each.payload.headers.map(head => {
if (head.name === 'From') {
sendObject.replyTo = head.value
} else if (head.name === 'Subject') {
if (head.value.indexOf('Re:') >= 0) {
sendObject.subject = head.value
} else {
sendObject.subject = 'Re: ' + head.value
}
} else if (head.name === 'Message-Id') {
sendObject.inReplyTo = head.value // The last thread messageId is inserted into In-Reply-To tag
sendObject.reference.push(head.value) // All the messageId are appended as part of References tag
}
})
})
const email_lines = []
email_lines.push('References:' + sendObject.reference.join(' '))
email_lines.push('In-Reply-To:' + sendObject.inReplyTo)
email_lines.push('Subject: ' + sendObject.subject)
email_lines.push('To:' + sendObject.replyTo)
email_lines.push('')
email_lines.push(req.body.body)
const email = email_lines.join('\r\n').trim()
let base64EncodedEmail = new Buffer(email).toString('base64')
base64EncodedEmail = base64EncodedEmail.replace(/\+/g, '-').replace(/\//g, '_')
emailConfig.gmail.users.messages.send({
userId: 'me',
threadId: sendObject.threadId,
resource: {
raw: base64EncodedEmail
}
}, async (err) => {
if (err) {
console.log('The Threads API returned an error: ' + err)
}
})
When i login to gmail through browser, i can see 2 different emails instead of one thread.
You should put threadId inside of the resource.
const response = await this.gmail.users.messages.send({
auth: this.oAuth2Client,
userId: this.gmailAddress,
uploadType: 'multipart',
resource: {
threadId: email.threadId,
raw: raw
}
})
For more details, you can check my Gmail-APIs-wrapper here
===================This is my code below=========================
function spotifyThisSong() {
var spotify = new Spotify({
id: 'myid',
secret: 'mysecret'
});
var songName = process.argv[3];
if(!songName){
songName = "What's my age again";
}
var params = songName;
spotify.search({ type: 'track', query: params }, function(err, data) {
if ( err ) {
console.log('Error occurred: ' + err);
return; //from spotify npm docs
}
else{
console.log(data);
};
});
}
===================END OF CODE=========================
keeps giving me undefine. I need to extract the song name, year, album and its url. Thanks in advance.
//So this is what I found. This actually involves a few things.
//FIRST, capture user-input,
//SECOND, npm install spotify, and use the template as suggested in the DOCS.
//THIRD, parse through the JSON correctly as done below.
//HOPE this helps someone. (dont forget your keys from spotify)
var songName = process.argv[3]; //capture userInput and query it below
params = songName;
spotify.search({ type: 'track', query: params }, function(err, data) {
if ( err ) {
console.log('Error occurred: ' + err);
return;
}
else{
output = space + "================= DATA HERE ==================" +
space + "Song Name: " + "'" +songName.toUpperCase()+ "'" +
space + "Album Name: " + data.tracks.items[0].album.name +
space + "Artist Name: " + data.tracks.items[0].album.artists[0].name +
space + "URL: " + data.tracks.items[0].album.external_urls.spotify + "\n\n\n";
console.log(output);
};
});
I am trying to get the real time tag subscription to work but it seems like the real time update only update within a minute. Here are my code, can you please point out what I am missing?
var Instagram = require('instagram-node-lib');
app.get('/GetInstagram', function(request, response){
// The GET callback for each subscription verification.
var params = url.parse(request.url, true).query;
response.send(params['hub.challenge'] || 'No hub.challenge present');
});
app.post('/GetInstagram', function (req, res) {
var tagName = 'love';
Instagram.set('client_id', 'clientID');
Instagram.set('client_secret', 'ClientSecret');
Instagram.tags.subscribe ({ object_id: tagName,access_token: null, client_id: 'clientid', client_secret: 'clientsecret', callback_url: 'http://myURL/GetInstagram', complete: function()
{
console.log('begin fetching');
Instagram.tags.recent({ name: tagName,aspect: 'media', complete: function(data, pagination )
{
var chunk = { 'pagination': pagination, 'data': data };
console.log (chunk.data.length);
var len = 0;
for (var i = 0, len = chunk.data.length; i < len; i++)
{
var url = '"' + chunk.data[i].images.standard_resolution.url + '"';
console.log('image from instagram image # ' + i + ' image URL' + chunk.data[i].images.standard_resolution.url );
}
res.end();
}
});
}
});
});
pretty sure you're not using the right method -- you want to use Instagram.subscriptions.subscribe for a real-time feed, not tags.subscribe