I am currently trying to implement SendGrid Email Activity into my application. Whenever an event fires I am able to access the info I need. When trying to look at the message corresponding to the message_id I receive the error: NOT FOUND.
I am wondering if there is a solution for this or has it not yet been created on SendGrid and how would I go about accessing the message information based on an engagement or delivery event?
Thanks
const env = require('dotenv').config();
const client = require('#sendgrid/client');
client.setApiKey(process.env.SENDGRID_API_KEY);
const eventStatus = info.event;
const customerAccountNumber = info.customerAccountNumber;
const recipient = info.email;
const messageId = info.sg_message_id;
console.log("message ID:", messageId);
try {
const request = {};
request.method = 'GET';
request.url = '/v3/messages/' + messageId;
client.request(request)
.then(([response, body]) => {
console.log(response.statusCode);
if(response.statusCode == 200) {
const messageInfo = response.body;
const sender = messageInfo.from_email;
const subject = messageInfo.subject;
console.log(eventStatus, customerAccountNumber, sender, recipient, messageId, subject);
}
else {
console.dir("Here");
}
});
}
catch(e){
console.log(e);
}
return("Test");
I believe you're getting a HTTP 404 because the URL you're putting together is wrong. Given messageId = 'foobar123', the following code
request.url = '/v3/messages/' + messageId;
will produce the request URL "/v3/messages/foobar123".
Taking a quick peek at the docs, the URL should be something more like "/v3/messages?limit=10&query={your_query}", with options for {your_query} described here.
I'm assuming you're trying to make a query such as msg_id="filter0307p1las1-16816-5A023E36-1.0". You need to pass this as URL parameter query. You'll also need to URL encode it, since it contains = and " characters. Putting all of this together, I'd try something like:
const query = `msg_id="${messageId}"`;
const request = {};
request.method = 'GET';
request.url = `/v3/messages?query=${encodeURIComponent(query)}`;
client.request(request).then(...)
Related
I have a node.js Function App which I'm trying to use to retrieve a specific message from a storage queue in order to delete it. It doesnt seem like there is a method to get a specific message by ID, so I'm trying to read all the messages, or at least 32 of them, then find the message to delete by ID.
My problem is I cant seem to figure out how to format the request to specify the number of messages to receive. I am trying to add the option "numberOfMessages" based on this documentation: https://learn.microsoft.com/en-us/javascript/api/#azure/storage-queue/queuereceivemessageoptions?view=azure-node-latest##azure-storage-queue-queuereceivemessageoptions-customheaders
Here is what I have right now that isn't working:
const response = await queueClient.receiveMessages({"numberOfMessages": 32});
context.log("response: " + JSON.stringify(response.receivedMessageItems));
context.log("received messages length: " + response.receivedMessageItems.length);
response is:
[Information] response: [{"messageId":"XXXXXX","insertedOn":"2022-08-28T06:12:45.000Z","expiresOn":"2022-09-04T06:12:45.000Z","popReceipt":"XXXXXXXXX","nextVisibleOn":"2022-08-30T14:57:37.000Z","dequeueCount":858,"messageText":"XXXXXXX"}]
[Information] received messages length: 1
How should I be formatting the option(s)???
edit:
Here is the complete code of index.js in my function app (with redactions):
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
const message = req.body;
const ackType = message.ackType;
if (ackType == 1){
const { QueueServiceClient, StorageSharedKeyCredential } = require("#azure/storage-queue");
const account = "MY_ACCOUNT_NAME";
const accountKey = "MY_ACCOUNT_KEY";
const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
const queueServiceClient = new QueueServiceClient(
`https://${account}.queue.core.windows.net`,
sharedKeyCredential,
{
retryOptions: { maxTries: 4 } // Retry options
}
);
const queueName = "MY_QUEUE_NAME";
const queueClient = queueServiceClient.getQueueClient(queueName);
const response = await queueClient.receiveMessages({"numofmessages": 32});
context.log("response: " + JSON.stringify(response));
context.log("receivedMessageItems: " + JSON.stringify(response.receivedMessageItems));
context.log("received messages length: " + response.receivedMessageItems.length);
}
context.res = {
status: 200 /* Defaults to 200 */
};
}
Here is the queue I am connecting to:
I've following code snippet to get the "Controller" (The owner of the domain) but I need to get the "Registrant" of provided ENS name
const Web3 = require("web3")
const web3 = new Web3("https://cloudflare-eth.com");
var ens = web3.eth.ens;
var names = ['jtimberlake.eth', 'usman.eth'];
(async () => {
for (let domainName of names) {
// console.log('checking: ' + domainName);
const addr = await getDomain(domainName);
console.log(addr);
}
})();
async function getDomain(word) {
try {
const addr = await ens.getAddress(`${word}`)
// console.log(addr);
return addr;
} catch (err) {
console.error(err);
return;
}
}
Can you please guide how I can get the "Registrant" of provided ENS name e.g. jtimberlake.eth
Web3 is a steaming pile. It doesn't do it with its methods. The registrant used to be called the deed owner, and the controller the owner. Now it is registrant and controller. That's why the method name makes no sense at all now in Web3.js - it never got updated, and never was useful for this in the first place.
The good news is there is a simple way. You can derive the token ID of the ENS domain from its name with the getRegistrant function below. https://docs.ens.domains/dapp-developer-guide/ens-as-nft
The name variable in the docs is superfluous and does nothing. You will need to instantiate ethersjs (npm install ethers) to get the ethers methods to work. You have to use this crazy number of functions because the token ID of an ENS domain/NFT is a uint256. JavaScript hates those natively.
The web3 method to find the controller also still works well if you ever need that. I suggest putting it in another function.
const getRegistrant = (domainName) => {
const BigNumber = ethers.BigNumber
const utils = ethers.utils
const labelHash = utils.keccak256(utils.toUtf8Bytes(domainName))
const derivedTokenId = BigNumber.from(labelHash).toString()
//You need to instantiate the ENSRegistrarContract with its ABI and address. e.g. const ENSRegistrarContract = new web3.eth.Contract(ABI, ADDRESS)
ENSRegistrarContract.methods.ownerOf(derivedTokenId).call()
.then(function(registrant) {
console.log(domainName + "is owned by: " + registrant)
return registrant
})
}
const getController = (domainName) => {
//getOwner fetches the controller of a domain confusingly.
web3.eth.ens.getOwner(domainName).then(function(controller) {
console.log(domainName + "is controlled by: " + controller)
return controller
})
}
After connecting and wiring the Shelly2.5 with my shutter, trying to connect it with Siri.
Decided to do this with Scriptable app and then connect Siri commands to it, so it will run.
Currently have an issue to send the request from the Scriptable app as the code is written below, when i tried to fire it from Postman it works.
// # open shutter
let url = "https://domain.shelly.cloud";
let suffix ="/device/relay/roller/control/";
let auth_key = "AAAABBBBCCCDDDEEEEFFFFFF____EXAMPLE_TOKEN___AAAABBBBCCCDDDEEEEFFFFFF";
let channel = 0;
let turn = "on";
let direction = "open";
let id = "C45bbe75f1bd";
let body = {
"auth_key":auth_key,
"id": id,
"direction":direction
};
// console.log(body);
let req = new Request(url + suffix);
// console.log(url+suffix);
req.method = "POST";
req.body = body;
req.headers = { "Content-Type":"application/x-www-form-urlencoded" };
// req.body = JSON.stringify(body)
let json = await req.loadJSON()
console.log(json);
the current response:
2021-09-13 11:20:46: {"isok":false,"errors":{"invalid_header":"Unauthorized! Wrong authorization header provided!","invalid_token":"The login information is invalid! Please login again!"}}
please notice that i change the real token and the real sub domain for shelly cloud.
It will be grate if someone know how to fix this, Thanks
looks like the Shelly expect form-encoded body. Try this
let form = Object.keys(body).map( k => `${k}=${encodeURIComponent(body[k])}`).join('&')
req.body = form
So watch a tutorial on internet i created a Google App Script(GAS) for getting History id. using previous history ids i created a script which gives message id and thread id for every incoming requests and posts it on my API in function postReq(). Now when i try to use these ids in python gmail api they show error that they dont exist. I tried to get ids for certain messages and found out they are different from those given from GAS. Is this something api does or i can fix this anyway? Thanks
function doPost(e) {
let message = JSON.parse(e.postData.getDataAsString()).message
let data = Utilities.newBlob(Utilities.base64Decode(message.data)).getDataAsString();
let sheet = SpreadsheetApp.openById('...')
let doc = DocumentApp.openById('...').getBody()
let para = doc.getParagraphs()[0]
let prevId = sheet.getDataRange().getValues()[0][0];
data = JSON.parse(data)
let historyId = parseInt(data.historyId)
let history = Gmail.Users.History.list("nyxgodxd#gmail.com",{"startHistoryId": `${prevId}` }).history
let threadId = history[0].messages[0].threadId
let msgId = history[0].messages[0].id
let msg = Gmail.Users.Messages.get(userId = 'me', id = `${msgId}`).snippet
let res = {historyId,threadId, msgId,msg}
para.appendText(`\n${JSON.stringify(res)}\n`)
postReq(res)
sheet.getDataRange().setValues([[`${historyId}`]])
return 200;
}
I have an input that sends an api call on submit to the unsplash API. I am trying to convert this into a netlify function but am not sure how to pass the params from the input into the function. I am trying to keep the API key hidden. I've never worked with the qs package and looked up the docs but have not been able to quite figure it out.
script.js
const KEY = "" //secret
const URL = `https://api.unsplash.com/search/photos?page=1&per_page=50&client_id=${process.env.KEY}`;
const input = document.querySelector(".input");
const form = document.querySelector(".search-form");
const background = document.querySelector(".background");
const overlay = document.querySelector(".overlay");
const header = document.querySelector(".title");
let results = [];
search = (searchTerm) => {
let url = `${URL}&query=${searchTerm}`;//this should hit the netlify endpoint instead
return fetch(url)
.then((response) => response.json())
.then((result) => {
toggleStyles();
header.appendChild(form);
result.results.forEach((image) => {
const galleryItem = document.createElement("div");
galleryItem.className = "gallery-item";
const imageDiv = document.createElement("div");
imageDiv.className = "image-div";
document.querySelector(".results-page").appendChild(galleryItem);
galleryItem.appendChild(imageDiv);
imageDiv.innerHTML =
"<img class='image' src=" + image.urls.regular + ">";
form.classList.remove("toggle-show");
input.classList.add("header-expanded");
form.addEventListener("submit", (e) => {
e.preventDefault();
document.querySelector(".results-page").remove();
});
});
console.log(result.results);
return results;
});
};
toggleStyles = () => {
const resultsContainer = document.createElement("div");
resultsContainer.className = "results-page";
document.body.appendChild(resultsContainer);
};
input.addEventListener("focus", (e) => {
e.preventDefault();
input.style = "font-family: 'Raleway', sans-serif";
input.placeholder = "";
});
input.addEventListener("blur", (e) => {
e.preventDefault();
input.style = "font-family: FontAwesome";
input.value = "";
input.placeholder = "\uf002";
});
form.addEventListener("submit", (e) => {
e.preventDefault();
let searchTerm = input.value;
search(searchTerm);
});
token-hider.js
const axios = require("axios");
const qs = require("qs");
exports.handler = async function (event, context) {
// apply our function to the queryStringParameters and assign it to a variable
const API_PARAMS = qs.stringify(event.queryStringParameters);
console.log("API_PARAMS", API_PARAMS);
// Get env var values defined in our Netlify site UI
// TODO: customize your URL and API keys set in the Netlify Dashboard
// this is secret too, your frontend won't see this
const { KEY } = process.env;
const URL = `https://api.unsplash.com/search/photos?page=1&per_page=50&client_id=${KEY}`;
console.log("Constructed URL is ...", URL);
try {
const { data } = await axios.get(URL);
// refer to axios docs for other methods if you need them
// for example if you want to POST data:
// axios.post('/user', { firstName: 'Fred' })
return {
statusCode: 200,
body: JSON.stringify(data),
};
} catch (error) {
const { status, statusText, headers, data } = error.response;
return {
statusCode: error.response.status,
body: JSON.stringify({ status, statusText, headers, data }),
};
}
};
I added the KEY as an Environment variable in my netlify UI, and am able to hit the function's endpoint. Any help is greatly appreciated as I am new to serverless functions but want to learn JAMstack really badly.
I think you are asking two different things here - how to use secret keys in Netlify functions and how to pass parameters to it from your front end code.
You can define environment variables in your Netlify site settings. These variables can then be used in your Netlify functions via process.env. So if you called your variable SECRET_KEY, then your Netlify function code (not your front end code!) would be able to read it via process.env.SECRET_KEY.
Looking over your code, it looks like you understand that as you have it in your function, but you also try to use it in the client-side code. You can remove that.
Your code gets the query string parameters, and it looks like you just need to add them to the end of the URL you hit. Did you try that?