Parse main.js Mandrill HTML mail sending issue - javascript

I have a cloud function on Parse in main.js where I send mail as HTML encoded with Mandrill API. I call this function through my iOS app posting some parameters and its perfectly ok, sends the email. However I want to localize the HTML body depending on the language of user. Since I checked the iOS in-line HTML options which are very tricky, I'm trying to do it in my sendMail function on main.js:
Parse.Cloud.define("sendMail", function(request, response) {
var Mandrill = require('mandrill');
Mandrill.initialize('APP_ID');
var locale = request.params.locale;
var userName = request.params.user;
var password = request.params.pass;
var HTMLBodyEn = '<p>text</p>';
var HTMLBody = HTMLBodyEn;
if (locale == 'tr') {
HTMLBody = '<p>yazı</p>';
}
Mandrill.sendEmail({
message: {
html: HTMLBody,
subject: request.params.subject,
from_email: request.params.fromEmail,
from_name: request.params.fromName,
to: [
{
email: request.params.toEmail,
name: request.params.toName
}
]
},
async: true
},{
success: function(httpResponse) {
console.log(httpResponse);
response.success("Email sent!");
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh oh, something went wrong");
}
});
});
Well it's simple as that. If condition you see there causes all the problem... As you can see there I'm receiving a locale key to change the body but it doesn't and Parse returns 141 error code which means after some digging is a time-out exception.
I can't seem to understand that a simple if statement as that causes a timeout.
Can anyone help me on this? Encountered anything similar?

You might be experiencing side effects from a text encoding issue. The Mandrill SDK on parse doesn't appear to handle the charset you're using. Take a look at this post from their forums that offers a workaround for that problem.
https://www.parse.com/questions/sometimes-getting-mandrill-you-must-specify-a-key-value-error-when-sending-email

Related

Fetch failing for Post to API

I have a route on my express server: /api/users/register.
When I pass data through VIA postman I am able to register an account. However on the front-end react side I am getting: TYPE ERROR: Failed to Fetch. Here is the code
handleSubmit = (event) => {
event.preventDefault();
const isValid = this.validateForm();
console.log(isValid);
if(isValid) {
let user = {
"username" : this.state.username,
"email" : this.state.email,
"password" : this.state.password
}
var json = JSON.stringify(user);
console.log(user);
fetch('https://URL/api/user/register', {
method: 'POST',
body: json,
headers: {
'Content-Type' : 'application/json'
}
}).then(function() {
console.log('ok');
}).catch(function(err){
console.log(err);
});
}
}
Its failing on the client side and I am not sure why. I am using POST methods else where and those are working just fine. I am stuck and have been for the last day. Any ideas on what's going on?
EDIT: I realize I am getting: ERR_CERT_COMMON_NAME_INVALID from Chrome on the URL but now I am not sure how to fix this.
You are likely hitting the changes in the way latest Chrome handles SSL certs. As of Chrome 58 I believe, they deprecated CNs altogether so if you are using self-signed dev certificate (or certificate that does not have proper SAN/Subject Alternative Name) you are likely to see this error. There has been a fair bit of commotion as many commercial products now find their code broken in Chrome.
Here is Google support article on the subject: https://support.google.com/chrome/a/answer/7391219
The best solution would be to update the server certs. If it is not feasible AND you are running on Windows, in some limited number of cases you could use this registry hack as a temporary workaround:
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome]
"EnableCommonNameFallbackForLocalAnchors"=dword:00000001
Hope that helps

Status Code 422 when trying to attach a file to an outlook calendar event

I'm trying to attach a text file to an existing Event in Outlook using graph-js-sdk-web.js I believe I followed instructions exactly but I get a 422 response. How do I get it to attach a file?
I'm pretty sure my eventID is correct because I can create an event and get it by that id. I'm pretty sure that my file's post load is correct because I attached file myself and then got that event by its id expanding for attachments and it was identical OData type, name, and content.
So far I googled the response and everything I've seen is either it just works for people or they were off on their code compared to that example.
Here are permissions I'm requesting
openid profile User.Read MailboxSettings.Read Calendars.ReadWrite
This matches permissions granted to the registered app.
This is the client and file attachment code:
// Create a Graph client
var client = MicrosoftGraph.Client.init({
authProvider: (done) => {
// Just return the token
done(null, sessionStorage.accessToken);
}
});
client
.api('/me/calendar/events/' + eventID + '/attachments')
.post({
attachment: {
"#odata.type": "#microsoft.graph.fileAttachment",
name: "helloworld.txt",
contentBytes: "SGVsbG8gd29ybGQh"
}
}, (error, response) => {
if (error)
console.log(error);
else {
console.log(response);
}
});
that produced this request payload
{
"attachment":{
"#odata.type":"#microsoft.graph.fileAttachment",
"name":"helloworld.txt",
"contentBytes":"SGVsbG8gd29ybGQh"
}
}
the response I get from this is
{
"error": {
"code": "UnprocessableType",
"message": "Cannot process input of abstract type 'Microsoft.OutlookServices.Attachment'",
"innerError": {
"request-id": "0a81e9f9-ef64-4b5e-b854-65e24fb71cfb",
"date": "2019-05-14T23:57:29"
}
}
}
I'm not seeing what does it need to process attachment. What I find odd is that its abstract base class, not the one I provided in the odata.type field, which could be nothing.
I opened graph explorer and even though they don't have a working sample for attaching to event I used a post with this payload and my url and got the exact same response 422. That tells me its not the js library its something off with the graph api itself, either setup is different from their documentation or we are missing some undocumented setup requirement.
Thanks to jasonjon's help the problem is solved. In the referenced instructions there's a mismatch in the payload example and javascript code sample. I went with js sample and had parent node attachment in the payload. Turns out there is no parent node. The correct way to use that api is
client
.api('/me/calendar/events/' + eventID + '/attachments')
.post({
"#odata.type": "#microsoft.graph.fileAttachment",
name: "helloworld.txt",
contentBytes: "SGVsbG8gd29ybGQh"
}, (error, response) => {
if (error)
console.log(error);
else {
console.log(response);
}
});

Sending a welcome email parse cloudcode with mailgun

I have a working mailgun server in my parse cloudcode for an iOS app. I have set up a series of emails to be triggered by status changes in the database. I have now set up a welcome email that was formerly hard coded into the app. I have it set up as an afterSave however during the app the user is saved more than once, causing the welcome to be triggered. Is there a way I can only send this out once, or do I have to make it specific to a new user registering in the function if that is possible. Thanks.
Parse.Cloud.afterSave(Parse.User, function(request) {
console.log("aftersave fired");
if(!request.user.existed()){
var email = "Hello and welcome";
var subject = "Welcome to W!";
var recipient = request.user.get("email");
console.log(recipient);
Mailgun.sendEmail({
to: "#gmail.com",
from: "#gmail.com",
subject: subject,
text: email
}, {
success: function(httpResponse) {
response.success();
},
error: function(httpResponse) {
response.success();
}
});
}
});
You can do something as simple as set a flag in a new column on the User class which indicates that they have been welcomed. When the user is saved, check that flag and decide wether to send or not (and update the flag).

What is the syntax for deleting/releasing Twilio phone numbers in Node.js?

I'm getting a 404 error when trying to delete a Twilio phone number via the API.
Here's my code:
var twilioSID = user.numberSID; // PN946a0603c974be563c5916f865be4d0b
var accountSid = '{removed}';
var authToken = '{removed}';
var client = require('twilio')(accountSid, authToken);
client.incomingPhoneNumbers(twilioSID).delete(function(err, deleted) {
if (err){
console.log(err);
} else {
console.log('Deleted from Twilio');
}
});
Here is the error I'm getting in the console:
{
status: 404,
message: 'The requested resource /2010-04-01/Accounts/{removed}/IncomingPhoneNumbers/PN946a0603c974be563c5916f865be4d0b.json was not found',
code: 20404,
moreInfo: 'https://www.twilio.com/docs/errors/20404'
}
The Twilio API doesn't have hardly any documentation for deleting numbers either. Any ideas on why this is not working?
#parkeragee Your solution is working
client.incomingPhoneNumbers(poneNumberSID).delete(function(err, deleted) {
if (err){
console.log(err);
} else {
console.log('Deleted from Twilio');
}
});
They changed it from delete to remove in their node js module.
As of this writing, the function to remove Twilio phone numbers via the API is called remove. If you try to use delete, you should receive the following error:
client.incomingPhoneNumbers(...).delete is not a function
I wasn't able to find any reference in the Twilio API docs; found this by reading the source, Luke.
Here's an example invoking remove:
client.incomingPhoneNumbers(sid).remove()
.then(function(deleted) {
// Success
})
.catch(function(error) {
// Handle error
});
According to their REST API documentation, you can send an HTTP DELETE request to a url like /2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers/{IncomingPhoneNumberSid}. So the URL in the error message looks almost right, except for the .json on the end. Either way it looks like a bug in their code if the phone number is in fact still attached to your account.
My issue was that I was overwriting my production phone nuber numberSID variable with my test phone number. So the user.numberSID; that I was assigning to a variable was for the Twilio test phone numbers. So, when it was searching for that numberSID, it returned a 404.

Parse custom webhook: can I query my tables?

In a Parse custom webhook, which is of the form:
app.post('/receiveSMS', function(req, res) {
Where receiveSMS is hooked up to the Twilio api and this method is properly called (I have logs to prove it), but I'm trying to query on my tables within this method and it doesn't seem to be working.
Is this allowed, or is there anything special I need to do to make this work?
var contactObj = Parse.Object.extend("Contact");
var contactQuery = new Parse.Query(contactObj);
console.log(req.body.From);
contactQuery.each(function(contact) {
and the body of the each call never gets called.
Is this allowed, and if so, what am I doing wrong here?
Update -- The entirety of the webhook code block is:
app.post('/receiveSMS', function(req, res) {
console.log('receive SMS');
console.log(req.body.Body);
res.send('Success');
if(req.body.Body.toLowerCase() == "in" || req.body.Body.toLowerCase() == "out") {
twilio.sendSMS({
From: "(xxx) xxx-xxxx",
To: req.body.From,
Body: "It's been noted, and notifications have been sent. Check us out!"
}, {
success: function(httpResponse) {
console.log(httpResponse);
response.success("SMS Sent!");
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh OH, something went wrong");
}
});
if(req.body.Body.toLowerCase() == "in") {
console.log("in was received");
// eventQuery
var contactObj = Parse.Object.extend("Contact");
var contactQuery = new Parse.Query(contactObj);
console.log(req.body.From);
// contactQuery.equalTo("phone", req.body.From);
contactQuery.first({
success: function(contact) {
console.log("found contact");
console.log(contact);
}, error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
}
});
This code is called and the logs "console.log('receive SMS')" and the like are all called, except for what is inside the query's first call.
Queries on tables is fine, but you can't use the each() function, as that is restricted to only work in background jobs.
You'll have to use find() or first() or get() depending on your needs.
UPDATE
OK, after seeing your full code I have some ideas as to why it isn't working. First off you're sending res.send("Success"); before you're finished, I'm not positive but I think this causes it to stop running the rest of your code (haven't checked, could be wrong).
Also you're doing multiple async operations without chaining them so the contactQuery.first() will run before the twilio.sendSMS() is finished.
Inside twilio.sendSMS() you're calling response.success() / response.error(). These are for cloud methods, not web hooks, so I expect these would be throwing errors server-side (check the logs on the Dashboard).
Inside contactQuery.first() you are using alert() which isn't supported in cloud code.
I'm not sure if those mistakes will be caught early and throw errors or if they'll raise run-time exceptions, but they should be fixed, your code re-deployed and try again. Then report any errors in the server logs.
Yes, it's allowed, I'm using the same web hooks.
My guess is that you probably have defined security restriction on your Contact class that prevent the query to fetch anything. What's the security setting on this class ?
You can either try to relax the constrains, or login as a dummy user, and execute the query (approach that I chose).
cheers
-A

Categories

Resources