mailgun.js inline image attachments - javascript

I want to embed inline images with mailgun, however the documentation for sending attachments doesnt seem to match with the latest mailgun.js NOT mailgun-js
https://www.npmjs.com/package/mailgun.js
the mentioned docs in this readme do not exist: https://documentation.mailgun.com/api-sending.html#sending << 404's
The readme docs for this version say this:
But where do I even add an attachment? How do I set mailgun to use multipart/form-data encoding? Where/ what parameter do I use to add an attachment? There are no good type definitions either
If i have this code below, how do I just add an attachment? What's the object schema? Does it even go here? I have no clue
mg.messages.create('sandbox-123.mailgun.org', {
from: "Excited User <mailgun#sandbox-123.mailgun.org>",
to: ["test#example.com"],
subject: "Hello",
text: "Testing some Mailgun awesomness!",
html: "<h1>Testing some Mailgun awesomness!</h1>"
})
Even once set as an attachment, how do I reference it in the email to use in <img> ?
Anyone that has done with the latest mailgun.js please share your reference code. The documentation is outdated

The documentation of mailgun.js can be a bit confusing, at least for node JS, since their website refers to the old version SDK whereas their github page points to the new one. That said, their github page does offer examples for including figures in the email. There are two ways to do so
Sent as attachment files but NOT displayed in the email.
Sent as inline figure and displayed in the email.
Below shows an example (original code available here) of sending figures both as attachment and inline. Notice that for inline figures to display, one must anchor the file name with a prefix cid: in an HTML template.
To send multiple attachments or inline figures, include all files in a list (the example below uses a list of one file for both inline and attachment).
/**
Copied from https://github.com/mailgun/mailgun-js/blob/master/examples/send-email.js
*/
const fs = require('fs');
const domain = 'sandbox-123.mailgun.com';
const fromEmail = 'Excited User <mailgun#sandbox-123.mailgun.com>';
const toEmails = ['you#example.com'];
const mailgunLogo = fs.createReadStream(`${__dirname}/mailgun.png`);
const rackspaceLogo = fs.createReadStream(`${__dirname}/rackspace.png`);
mg.messages.create(domain, {
from: fromEmail,
to: toEmails,
subject: 'Hello',
html: '<img src="cid:mailgun.png" width="200px"><br><h3>Testing some Mailgun awesomness!</h3>',
text: 'Testing some Mailgun awesomness!',
inline: [mailgunLogo],
attachment: [rackspaceLogo]
})
.then((msg) => console.log(msg))
.catch((err) => console.log(err));

Related

How to get file extension from file content using Node.js

I need some help. I need to fetch what the file type should be from the file containing only using Node.js. I am explaining the scenario below.
Let's say I have some content like below.
let fileContent = "The textContent property sets or returns the text content of the specified node, and all its descendants."
As we can see here the variable fileContent has some text data and I want to write this data into one file. So for that, I need to create the file with a proper extension like abc.txt. Similarly, If fileContent has some json data then I will create the file like abc.json and write the value inside it.
So here I need to fetch what should be the type of file from this content only using Node.js. If anybody has a solution for this will be a great help.
You can use popular file-type package for this. You can send buffer/file/stream/blob as an input and get file type as an output.
const FileType = require('file-type');
...
const { ext, mime } = await FileType.fromBuffer(your_data);

Add Signature field to pdf in javascript

after hours of searching for a solution, I've decided to ask my first question on stackoverflow.
Our application uses pdf-lib (https://www.npmjs.com/package/pdf-lib) to modify existing PDFs, e.g. add images. We're now looking for a way to ad signature form fields to the PDF as well.
With pdf-lib, it is possible to add a bunch of form fields, except for signature fields. It is possible to get them (https://pdf-lib.js.org/docs/api/classes/pdfform#getsignature), but unlike other fields, there's no create method (e.g. https://pdf-lib.js.org/docs/api/classes/pdfform#createtextfield).
I've digged deeper in the code, and found access to the PDFForms AcroForm (https://pdf-lib.js.org/docs/api/classes/pdfform#acroform). It's possible to add fields with it, but I wasn't able to create the correct Field beforehand (in my opinion it has to be PDFSignature or PDFAcroSignature).
I found out that other fields like PDFAcroText have create methods
class PDFAcroText extends PDFAcroTerminal {
static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroText(dict, ref);
static create = (context: PDFContext) => {
const dict = context.obj({
FT: 'Tx',
Kids: [],
});
const ref = context.register(dict);
return new PDFAcroText(dict, ref);
};
Those get called by the wrapper functions (like createTextfield as mentioned):
createTextField(name: string): PDFTextField {
assertIs(name, 'name', ['string']);
const nameParts = splitFieldName(name);
const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal);
const text = PDFAcroText.create(this.doc.context);
text.setPartialName(nameParts.terminal);
addFieldToParent(parent, [text, text.ref], nameParts.terminal);
return PDFTextField.of(text, text.ref, this.doc);
}
I looked for other js libs that provide the possibility to add signature form fields, but I wasn't able to find the answer to this - except for pay to use libs like pdfjs.express.
Assuming that they are capable of adding such fields, there must be a way to do this!
Please let me know if anyone of you figured out how to do this or if there's another solution for this.
Thank you in advance!
Greetings
Alex
The Acrobat PRO itself doesn't have an option to put a straight "Signature" field. You may "request" a signature, but only using Adobe's services, and an email is required.
If you plan to add a signature by the code, take a look at their "Fill Form" example. They put an image on top of a Button field, but an Image field also works.
const signatureImageField2 = form.getButton('button-signature-field')
signatureImageField2.setImage(signatureImage)
const factionImageField = form.getField('image-signature-field_af_image')
factionImageField.setImage(signatureImage)

When I add "METHOD: REQUEST" to iCalendar, Gmail stops recognizing as event

I'm using iCalendar to schedule events for Gmail users. However, I want to be able to send updates, if/when the event changes. I read that I must use METHOD:REQUEST in order to allow updates.
However, when I add the METHOD:REQUEST to my ics file, Gmail stops recognizing it as a calendar invite.
Here is the working example WITHOUT "METHOD:REQUEST"
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Cratic//Cratic Huddle//EN
NAME:Cratic Huddle
X-WR-CALNAME:Cratic Huddle
TIMEZONE-ID:Europe/Berlin
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VEVENT
UID:60212c8395841f2cd057864f#cratic.ai
SEQUENCE:0
DTSTAMP:20210208T130601Z
DTSTART:20210219T133059Z
DTEND:20210219T140059Z
SUMMARY:Cratic Huddle
DESCRIPTION:This is the information
ORGANIZER;CN="Izzi":mailto:firstname.lastname#gmail.com
ATTENDEE;ROLE=REQ-PARTICIPANT:MAILTO:firstname.lastname#gmail.com
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
DESCRIPTION:Cratic Huddle
END:VALARM
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15M
ATTACH;VALUE=URI:Basso
END:VALARM
URL;VALUE=URI:cratic.ai
END:VEVENT
END:VCALENDAR
The above works perfectly; Gmail pops up with a button asking if I want to accept.
Here is the NOT working example WITH "METHOD:REQUEST"
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Cratic//Cratic Huddle//EN
METHOD:REQUEST
NAME:Cratic Huddle
X-WR-CALNAME:Cratic Huddle
TIMEZONE-ID:Europe/Berlin
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VEVENT
UID:60212c8395841f2cd057864f#cratic.ai
SEQUENCE:0
DTSTAMP:20210208T125937Z
DTSTART:20210219T133059Z
DTEND:20210219T140059Z
SUMMARY:Cratic Huddle
DESCRIPTION:This is the information
ORGANIZER;CN="Izzi":mailto:firstname.lastname#gmail.com
ATTENDEE;ROLE=REQ-PARTICIPANT:MAILTO:firstname.lastname#gmail.com
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
DESCRIPTION:Cratic Huddle
END:VALARM
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15M
ATTACH;VALUE=URI:Basso
END:VALARM
URL;VALUE=URI:cratic.ai
END:VEVENT
END:VCALENDAR
This generates a blank email in google, with the .ics file attached. It does not appear in the calendar or anywhere else.
These two iCalendar files are identical in every other way. But for some reason adding the METHOD:REQUEST is killing the ics file / google's ability to read it.
Why??
Ok - After many hours of reading RFC5546, Stackoverflow, and many other blogs, I finally have the answers.
Scope:
Sending calendar invites to Gmail / Outlook / Privateemail (namecheap's email client)
Email clients automatically recognizing .ics files and generating "accept" templates
Events automatically appearing in client calendars as "tentative"
Sending event revisions that automatically move client calendar events
There are two fundamental principles that are critical to making this work:
The contents of the .ics file must very closely match the .ics file of the Gmail / Outlook community, this includes the parameters and the order of the parameters.
The way the .ics file is attached to the email transmission is odd but critical: (a) the .ics file must be turned into 'base64', and (b) the headers of the file need to give a type: 'text/calendar;method=REQUEST;name="file.ics"'
Below I will give examples of each, which I hope save others time on this process.
.ics Content Example:
let iCal =
`BEGIN:VCALENDAR
PRODID:-//Cratic//_Scheduler//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VEVENT
DTSTART:${DTStart}
DTEND:${DTEnd}
DTSTAMP:${DTStamp}
ORGANIZER;CN=name:mailto:name#gmail.com
UID:${event._id}#url.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=name#outlook.com;X-NUM-GUESTS=0:mailto:name#outlook.com
CREATED:${DTStamp}
DESCRIPTION:${event.body}
LAST-MODIFIED:${DTStamp}
LOCATION:${location}
SEQUENCE:${sequence}
STATUS:CONFIRMED
SUMMARY:${event.title}
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR`
Please note: the above ordering is very important! And you must have no dead spaces around the text, even one extra space before or after will disrupt the email client. Also, this is a reusable dynamic iCal event template, as long as I keep a record of the event._id, I can use that _id to send revisions to all my clients.
Attaching .ics to Email Client:
// convert the invite to be base64 for attachment
const buf = Buffer.from(iCal.toString(), 'utf-8');
const base64Cal = buf.toString('base64');
// build the email
const sendEmail = async () => {
const res = await client.transmissions.send({
recipients: [{ address: 'name#outlook.com' }],
content: {
from: 'name#sparkmail.com',
subject: req.body.a.title,
text: req.body.a.body,
attachments: [
{
name: 'invite.ics',
type: 'text/calendar;method=REQUEST;name=\"invite.ics\"',
data: base64Cal,
},
],
},
options: { sandbox: false },
});
}
// send the email
sendEmail();
Please note: The attachment type is critical for Outlook to recognize the event.
Although I'm sure there are other / better ways to integrate with these services, I found the above steps allowed me to accomplish my scope.

serverless - How to dynamically add resources generated from a javascript file and merge them with other resources?

I want to create a serverless file that deploys Cognito resources to AWS. I have a config.yml file that holds all the scopes that should be created in the Cognito Resource Server.
config.yml
- name: scope1
description: Description of scope1
- name: scope2
description: Description of scope2
What I want to accomplish is to dynamically generate one Cognito App Client for each scope we register, as well as adding these scopes to a Cognito Resource Server (in my case, the Cognito User Pool and Domain Name are already created).
To do that, I tried to make a javascript file that will load the config.yml file and generate two variables:
userPoolClientList which holds a list of Cognito App Client resources.
scopeList which represents a list of scopes that should be registered in the Cognito Resource Server.
sls-template.js
const fs = require("fs");
const yaml = require("js-yaml");
const scopeList = yaml.safeLoad(fs.readFileSync("config.yml"));
module.exports = {
scopeList: function () {
return scopeList.map(({ name, description }) => ({
ScopeName: name,
ScopeDescription: description,
}));
},
userPoolClientList: function (serverless) {
const { cognitoUserPoolId } = serverless.service.custom;
const scopeResourceList = scopeList.map(({ name, description }) => ({
[`cognitoUserPoolClient-${name}`]: {
Type: "AWS::Cognito::UserPoolClient",
Properties: {
AllowedOAuthScopes: [`server/${name}`],
UserPoolId: cognitoUserPoolId,
},
DependsOn: "cognitoResourceServer",
},
}));
return Object.assign({}, ...scopeResourceList);
},
};
Now this looks like it returns exactly what I wanted (I've tested it and it works great).
My problem is rather in the implementation on the serverless.yml file and how to combine a fixed Resources and a dynamically generated one.
serverless.yml
resources:
Resources:
${file(sls-template.js):userPoolClientList}
cognitoResourceServer:
Type: AWS::Cognito::UserPoolResourceServer
Properties:
Identifier: server
Name: Server
Scopes: ${file(sls-template.js):scopeList}
UserPoolId: ${self:custom.cognitoUserPoolId}
This throws an error as the syntax is not correct. However, when I try to deploy the resources individually (one time just the cognitoResourceServer resource, the other time the generated variable from the javascript file), everything works fine.
The problem really is on how I should combine or merge these two resources.
I've been trying a lot of different combinations to try to make it work, but it always give me an invalid template.
So I was wondering if what I try to accomplish is even possible in serverless and if so, how can I change my final serverless.yml file to make it work.
Thanks a lot.
Yes resource blocks can be merged.
I believe this should do it:
resources:
- Resources: ${file(sls-template.js):userPoolClientList}
- Resources:
cognitoResourceServer:
Type: AWS::Cognito::UserPoolResourceServer
Properties:
Identifier: server
Name: Server
Scopes: ${file(sls-template.js):scopeList}
UserPoolId: ${self:custom.cognitoUserPoolId}
Not 100% sure whether the dynamic block needs to generate Resources top-level key or whether you can hard-code it like I've shown in the example.

How to manipulate HTML table once it's returned from backend like Node.js?

Here's the situation: I use Node.js as my backend, and use markdown to edit and post my blog article. And when a client requests the specific URL, such as http://www.example.com/blog/article_1, I returned the blog contents from Node.js with some template like ejs, which would be something like the follows:
app.get("/blog/article1", function(req, res) {
var article = something // this is a valid HTML converted from a markdown file
res.render("article1", {
title: "my blog article 1",
article: article
});
});
In the above code, I render article.ejs with title and article variable. The article variable is a valid HTML to be injected to the ejs template. So far, it' fine.
However, if I want to display a HTML table which is written in the original markdown file, with Bootstrap 3's responsive table functionality, (i.e. <div class="table-responsive"><table class="table">...actual table...</table></div>), how can I do it? Right now the table in my markdown file is just a markdown file, and I don't think that it's the best idea to just modify all of my markdown files on which I insert or wrap with the <div class="table-responsive">...</div> line; the files might also be used in a situation other than Bootstrap.
In other words, is it feasible to dynamically or programmatically inject the responsive functionality to the table once the template is returned by Node.js? And is it also feasible to inject the responsive table functionality selectively? (in other words choose arbitrarily some tables that I want to add the responsive function?)
Continuing on from the comments: It's actually not that difficult to fork and modify a project. The faster you can get used to working with open source libraries the better your experience will be with Node. Things move pretty quickly in the Node world, and sometimes things won't work like they are expected to. You can either wait around for a fix, or roll up your sleeves and pitch in.
I found a way to update the markdown templates using their addTemplate method. However the version of Marked the project is using (2.8) doesn't support custom templates. I've forked the repository and updated the version of marked as well as fixed the issues this caused with the tests. I also added a restriction to prevent it from using Express 4 which breaks all the tests. I submitted these as a pull request to the original repo, but in the mean time you could use my version to write something like the following.
untested
var
express = require('express'),
app = express(),
Poet = require('poet'),
marked = require('marked'),
renderer = new marked.Renderer();
renderer.table = function(header, body) {
return '<div class="table-responsive"><table class="table">' + header + body + '</table></div>';
}
var poet = Poet(app, {
posts: './_posts/',
postsPerPage: 5,
metaFormat: 'json'
});
poet.addTemplate({ ext: 'markdown', fn: function(s) {
return marked(s);
}});
Alternatively, if all you're using poet for is the markdown conversion, you might as well use marked directly and cut out the dependency on poet.

Categories

Resources