Batch emailing with Mailgun and Node.js - javascript

I'm using the Mailgun node.js module to send batch emails out.
According to the big yellow warning message in the official docs, specifying recipient vars should result in sending "each recipient an individual email with only their email in the to field."
However, my recipients can see all of the "to" addresses. I am successfully using recipient-vars to set the email subject for users, so it does appear that these are being read in correctly.
Note that I am sending an HTML email using MIME. I tried this with the more straight-forward plain text variation, and it did appear to work.
Is anyone able to help me understand why my recipients can see all other recipients? Am I doing something wrong, or does this functionality not work for Mailgun MIME emails?
// recipients
var recipients = ['email1#email1.com', 'email2#email2.com', 'email3#email3.com'];
var recipientVars = {
'email1#email1.com': {
id: 1,
subject: 'Subject 1'
},
'email2#email2.com': {
id: 2,
subject: 'Subject 2'
},
'email3#email3.com': {
id: 3,
subject: 'Subject 3'
}
};
// options
var options = {
from: 'Me <me#me.com>',
to: recipients,
'recipient-variables': recipientVars,
subject: '%recipient.subject%',
text: myMailText,
html: myMailHTML,
headers: {
'X-Mailgun-Recipient-Variables': JSON.stringify(recipientVars)
}
};
// create mail
var mail = new nodemailer(options);
// send mail
mail.compile().build((err, message) => {
var mailData = {
to: recipients,
message: message.toString('ascii'),
'recipient-variables': recipientVars
};
mailgun.messages().sendMime(mailData, (err, res) => {
console.log(res);
});
});

Seems this functionality doesn't work with sendMime() method, but it does with regular send() method even without any mail compilation. Here is working code snippet:
const mailgun = require('mailgun-js')({
apiKey: 'api_key',
domain: 'domain'
});
const recipients = ['email1#gmail.com', 'email2#gmail.com'];
const recipientVars = {
'email1#gmail.com': {
id: 1,
subject: 'Subject 1',
name: 'Name 1'
},
'email2#gmail.com': {
id: 2,
subject: 'Subject 2',
name: 'Name 2'
}
};
const envelope = {
from: 'Sender <sender#gmail.com>',
to: recipients,
subject: '%recipient.subject%',
html: 'Hey <strong>%recipient.name%<strong>',
'recipient-variables': recipientVars,
};
mailgun.messages().send(envelope, function (error, body) {
console.log(body);
});
As you would notice all placeholders are populated and <strong> tag properly rendered.

Related

Interaction has already been acknowledged

I am currently having an issue with my /help command, the way my /help command works is it sends a nice fancy embed with a selectmenu that you can select different pages. That all works fine the issue comes when if I were to do /help and get the embed then do /help again and interact with the second embed it will crash and give the error "Interaction has already been acknowledged" Here is my code.
const generalHelp = { // Creates generalHelp embed.
color: 0x901ab6,
title: 'join our support server!',
url: 'https://discord.gg/MUwJ85wpKP',
author: {
name: 'Help Menu',
icon_url: 'https://cdn.discordapp.com/attachments/937276227692150815/937552170520301588/Letter_Z.png',
},
description: 'Select an option to view the commands I have!',
fields: [
{
name: ':tada: Fun Commands',
value: 'Shows all the bots varying fun commands in a nice little page for easy viewing.',
inline: true,
},
{
name: ':tools: Admin Commands',
value: 'Shows all the bots varying admin commands in a nice little page for easy viewing.',
inline: true,
},
/*{
name: '\u200b',
value: ' \u200b ',
inline: false,
},*/
],
}
const adminHelp = { // Creates moderationHelp embed.
color: 0x901ab6,
author: {
name: 'Help Menu',
icon_url: 'https://cdn.discordapp.com/attachments/937276227692150815/937552170520301588/Letter_Z.png',
},
description: 'Here are the commands!',
fields: [
{
name: 'Prefix: `/`',
value: '\u200b',
},
{
name: ':tools: Admin Commands',
value: '`toggle`, `settings`'
},
]
}
const funHelp = { // Creates funHelp embed.
color: 0x901ab6,
author: {
name: 'Help Menu',
icon_url: 'https://cdn.discordapp.com/attachments/937276227692150815/937552170520301588/Letter_Z.png',
},
description: 'Here are the commands!',
fields: [
{
name: 'Prefix: `/`',
value: '\u200b',
},
{
name: ':tada: Fun Commands',
value: '`ping`, `poll`',
},
]
}
const row = new MessageActionRow() // Creates MessageActionRow with name row.
.addComponents(
new MessageSelectMenu()
.setCustomId('select')
.setPlaceholder('Select an option')
.addOptions([
{
label: '🎉 Fun Commands',
description: '',
value: 'first_option',
},
{
label: '🔨 Admin Commands',
description: '',
value: 'second_option',
},
])
)
await interaction.reply({ embeds: [generalHelp], components: [row]}) // Displays general help embed
And here is my code that handles the interactions.
interaction.client.on('interactionCreate', interaction => { // Detects which value is selected.
if(!interaction.isSelectMenu()) return
if (interaction.values[0] === 'first_option') // Checks if values[0] is = to first_option to display gameHelp embed.
{
interaction.update({embeds: [funHelp]}) // Updates bots interaction embed
}
if (interaction.values[0] === 'second_option') // Checks if values[0] is = to second_option to display musicHelp embed.
{
interaction.update({embeds: [adminHelp]}) // Updates bots interaction embed
}
else // If values[0] is anything else display error message to console. (PM2 will auto restart bot if error happens.)
{
return//console.log('Help Menu Select Menu Error!') // Logging to PM2 console.
}
})
If someone could help me fix it that would be great <3
Its because you already .reply()-ed to the interaction, so the interaction is already acknowledged with that.
To solve this you can use .editReply():
interaction.reply({ content: 'This is my first reply!' });
interaction.editReply({ content: 'This my edited second reply!' });
For anyone still looking for an answer the reason this happens is because the first time it works 100% fine because there is no update and is a fresh interaction. However when you try and update it which also counts as an interaction. Putting your interactionCreate code into an event handler solves this issue.
module.exports = {
name: 'interactionCreate',
execute(interaction) {
//console.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`);
if (!interaction.isSelectMenu() && interaction.isCommand()) return
if (interaction.customId !== 'select') return
switch (interaction.values[0]) {
case 'first_option':
interaction.update({embeds: [funHelp], ephemeral: true})
break
case 'second_option':
interaction.update({embeds: [adminHelp], ephemeral: true})
break
default:
return
}
},
};

Discord.js converting Javascript with console into embeds for discord

So I'm working on a bot right now and when looking at the api I get this as the example of how it'll work.
(async () => {
console.log(await bookwebsite.getHomepage(1))
})()
{
results: [ { bookId: 'web id',
thumbnail: 'thumbnail link',
title: 'book title' },
{ bookId: 'web id',
thumbnail: 'thumbnail link',
title: 'book title' },
{ bookId: 'web id',
thumbnail: 'thumbnail link',
title: 'book title' },
...
],
}
Can anyone lead me in the right direction on how to translate this from a console log script to running it within discord embeds? API WARNING NSFW
I'm not extremely sure what you're meaning as of translating console into embeds but I'm guessing you're trying to format the data returned in the api in to a embed in Discord.
const bookwebsite = require('nhentai-js');
(async () => {
var data = await bookwebsite.getHomepage(1);
data = data.results.slice(0, 25);
if(!data) return message.channel.send('Failed to retrieve data from api. ')
// slices to avoid discord embeds going beyond 25 fields
var embed = new Discord.MessageEmbed()
.setTitle('Results found');
// For each the data that's received(after its trimmed)
data.forEach(d=>{
// For every object inside of data, it takes the name and sets it as a field title and sets the description of the field as the id and thumbnail link.
embed.addField(`Name: ${d.title}`, `ID: ${d.bookId}\nThumbnail: ${d.thumbnail}`)
})
// Embeds done, now need to send into the channel
message.channel.send(embed)
})()
If you need any help further on, please comment below.

MailGun: Add data variables to email

Im sending emails through Node.js using MailGun. I want to add custom data variables that contain data from database send it as part of email body. Based on my research I need to use recipient-variables. But the problem is that recipient-variables require the email of recipient as the key of the object like so:
{
"user1#example.com" : {"unique_id": "ABC123456789"},
"user2#example.com" : {"unique_id": "ZXY987654321"}
}
Now the data I'm getting from my database is this:
{ email: 'myemail#something.com', projects: [ 'aqeqw weqw ', 'title here' ]}
Whereas MailGun requires this (which seems weird to me):
{'myemail#something.com': { email: 'myemail#something.com', projects: [ 'aqeqw weqw ', 'title here' ]}}
How can I set the key of object I'm receiving from the database as the email?
FYI my code for MailGun:
let data = {
from: 'My App <donotreply#myapp.com>',
to: data.email,
subject: 'Reminder Email',
'recipient-variables': {data},
html: '<html style="color: red; font-size: 20px; background-color: aqua">Inline image here:<p style="">Your project list and your name is %recipient.projects%</p></html>',
};
mailgun.messages().send(data, function(error, body) {
console.log(body);
});
You can just do it like this, with an intermediate object:
let obj = {
email: 'myemail#something.com',
projects: [ 'aqeqw weqw ', 'title here' ]
}
let final = {}
final[obj.email] = obj
console.log(final)
/* {
'myemail#something.com':
{
email: 'myemail#something.com',
projects: [ 'aqeqw weqw ', 'title here' ]
}
}
*/

Get message_id from Telegram message - node.js

I have a problem concerning a Telegram bot I am currently working on. I get messages from users in the following format:
update { update_id: 82618016,
message:
{ message_id: 363,
from: { id: 22303518, first_name: 'Steve', language_code: 'de-DE' },
chat: { id: 22303518, first_name: 'Steve', type: 'private' },
date: 1501501753,
text: 'j' } }
When I want to access the id of the chat I can do this without any problems by using
$.message.chat.id
As soon as a want to get the message_id or first_name I only get "undefined".
$.message.chat.first_name
$.message.message_id
Can anyone help me here? As far as I see it I understood the structure of the message correctly so I don't really know what's the problem here.
Thank you very much in advance
EDIT: I am adding a bit more of my code here:
The main code for the bot (including the webhook) is this:
initializeBot();
function initializeBot(){
const Telegram = require('telegram-node-bot');
const PingController = require('./controllers/ping');
const OtherwiseController = require('./controllers/otherwise');
const tg = new Telegram.Telegram('MY_TOKEN_IS_HERE', {
webhook: {
url: 'https://xxx.herokuapp.com',
port: process.env.PORT || 443,
host: '0.0.0.0'
}
})
tg.router.when(new Telegram.TextCommand('/ping', 'pingCommand'), new PingController())
.otherwise (new OtherwiseController());
}
When the OtherwiseController gets called the following code is called (I reduced it to the essentials to clarify the problem.
class OtherwiseController extends Telegram.TelegramBaseController {
handle($){
console.log($.message.chat.first_name);
console.log($.message.text);
console.log($.message.chat.id);
console.log($.message.message_id);
}
}
The console output for this message
update { update_id: 82618020,
message:
{ message_id: 371,
from: { id: 22303518, first_name: 'Steve', language_code: 'de-DE' },
chat: { id: 22303518, first_name: 'Steve', type: 'private' },
date: 1501509762,
text: 'hello' } }
would be:
undefined
hello
22303518
undefined
Use the below method to extract the keys of your json object, then you can access with an appropriate key:
Object.keys($.message.chat);

Hyperlink not shown in gmail with email composer

I am trying to send html as a body with email composer. html body contains hyperlink but it is not working in gmail. Gmail display plain text only.
var email = {
to: sendersemail+';',
cc: '',
bcc: '',
attachments: [cordova.file.externalApplicationStorageDirectory+'Report.pdf'],
subject: '',
body: '<p>the brain out your I think you'll find it helpful too.</p>',
isHtml: true
};
$cordovaEmailComposer.open(email).then(null, function () {
// user cancelled email
});
use html instead of body!
var email = {
to: sendersemail+';',
cc: '',
bcc: '',
attachments: [cordova.file.externalApplicationStorageDirectory+'Report.pdf'],
subject: '',
html: '<p>the brain out your I think you'll find it helpful too.</p>'
};
$cordovaEmailComposer.open(email).then(null, function () {
// user cancelled email
});

Categories

Resources