What is wrong with this javascript regex string.replace? - node.js

UPDATE: I've discovered this problem is because of the "stringified" output which contains no spaces or newlines and is different than the original JSON.
Stringified output:
{"eventType":"Delivery","mail":{"timestamp":"2021-08-09T20:41:51.515Z","source":"removed#email.com","sourceArn":"arn:aws:ses:us-east-1:1234567890:identity/removed.com","sendingAccountId":"1234567890","messageId":"1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b","destination":["removedl#email.com"],"headersTruncated":false,"headers":[{"name":"From","value":"removed#email.com"},{"name":"To","value":"removed#email.com"},{"name":"Subject","value":"Test"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"7bit"}],"commonHeaders":{"from":["removed#email.com"],"to":["removed#email.com"],"messageId":"1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b","subject":"Test"},"tags":{"ses:operation":["SendEmail"],"ses:configuration-set":["GenericLog"],"ses:source-ip":["123.123.123.123"],"ses:from-domain":["email.com"],"ses:caller-identity":["user1"],"ses:outgoing-ip":["234.234.234.234"]}},"delivery":{"timestamp":"2021-08-09T20:41:52.880Z","processingTimeMillis":1365,"recipients":["removed#email.com"],"smtpResponse":"250 2.6.0 <1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b#email.amazonses.com> [InternalId=11231247472, Hostname=CO6PR12MB5396.namprd12.prod.outlook.com] 12090 bytes in 0.214, 55.135 KB/sec Queued mail for delivery","reportingMTA":"a48-108.smtp-out.amazonses.com"}}
ORIGINAL:
I want to remove the : from the key names and replace it with a _ in the following JSON. (In the tags section)
{
"eventType": "Delivery",
"mail": {
"timestamp": "2021-08-09T20:41:51.515Z",
"source": "removed#email.com",
"sourceArn": "arn:aws:ses:us-east-1:1234567890:identity/removed.com",
"sendingAccountId": "1234567890",
"messageId": "1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b",
"destination": [
"removedl#email.com"
],
"headersTruncated": false,
"headers": [
{
"name": "From",
"value": "removed#email.com"
},
{
"name": "To",
"value": "removed#email.com"
},
{
"name": "Subject",
"value": "Test"
},
{
"name": "MIME-Version",
"value": "1.0"
},
{
"name": "Content-Type",
"value": "text/plain; charset=UTF-8"
},
{
"name": "Content-Transfer-Encoding",
"value": "7bit"
}
],
"commonHeaders": {
"from": [
"removed#email.com"
],
"to": [
"removed#email.com"
],
"messageId": "1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b",
"subject": "Test"
},
"tags": {
"ses:operation": [
"SendEmail"
],
"ses:configuration-set": [
"GenericLog"
],
"ses:source-ip": [
"123.123.123.123"
],
"ses:from-domain": [
"email.com"
],
"ses:caller-identity": [
"user1"
],
"ses:outgoing-ip": [
"234.234.234.234"
]
}
},
"delivery": {
"timestamp": "2021-08-09T20:41:52.880Z",
"processingTimeMillis": 1365,
"recipients": [
"removed#email.com"
],
"smtpResponse": "250 2.6.0 <1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b#email.amazonses.com> [InternalId=11231247472, Hostname=CO6PR12MB5396.namprd12.prod.outlook.com] 12090 bytes in 0.214, 55.135 KB/sec Queued mail for delivery",
"reportingMTA": "a48-108.smtp-out.amazonses.com"
}
}
I've created a node.js Lambda function that is being called by AWS Kinesis. It processes the above JSON and the following code is being used. I am debugging, so I am simply trying to search and replace the string for testing:
console.log('Loading function');
exports.handler = async (payload, context) => {
payload = JSON.stringify(payload);
payload = payload.replace(/".*:.*":/g, 'replaced');
console.log('Replaced payload:', payload);
};
I've run the regex through multiple code testing sites and it correctly identifies all 6 occurrences of the key names with a : in them. I've even used this tester, and it correctly replaces all 6 strings as expected. But, when it runs on Lambda I get the following output:
Replaced payload: {replaced"a48-108.smtp-out.amazonses.com"}}
Am I missing something obvious or is this some weird thing happening in Lambda?
Note, if I simply output the unmodified payload variable it matches the input JSON, so that is not the issue.
I've got additional code which should complete this task successfully once I solve this mystery. But, if you could provide the code to replace : with _ in the key names, that would be great as well.

Expanding on your update comment:
UPDATE: I've discovered this problem is because of the "stringified" output which contains no spaces or newlines and is different than the original JSON.
You can add the following options to JSON.stringify to properly format the stringified output.
JSON.stringify(payload, null, 4);
Demo:
let payload = {"eventType":"Delivery","mail":{"timestamp":"2021-08-09T20:41:51.515Z","source":"removed#email.com","sourceArn":"arn:aws:ses:us-east-1:1234567890:identity/removed.com","sendingAccountId":"1234567890","messageId":"1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b","destination":["removedl#email.com"],"headersTruncated":false,"headers":[{"name":"From","value":"removed#email.com"},{"name":"To","value":"removed#email.com"},{"name":"Subject","value":"Test"},{"name":"MIME-Version","value":"1.0"},{"name":"Content-Type","value":"text/plain; charset=UTF-8"},{"name":"Content-Transfer-Encoding","value":"7bit"}],"commonHeaders":{"from":["removed#email.com"],"to":["removed#email.com"],"messageId":"1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b","subject":"Test"},"tags":{"ses:operation":["SendEmail"],"ses:configuration-set":["GenericLog"],"ses:source-ip":["123.123.123.123"],"ses:from-domain":["email.com"],"ses:caller-identity":["user1"],"ses:outgoing-ip":["234.234.234.234"]}},"delivery":{"timestamp":"2021-08-09T20:41:52.880Z","processingTimeMillis":1365,"recipients":["removed#email.com"],"smtpResponse":"250 2.6.0 <1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b#email.amazonses.com> [InternalId=11231247472, Hostname=CO6PR12MB5396.namprd12.prod.outlook.com] 12090 bytes in 0.214, 55.135 KB/sec Queued mail for delivery","reportingMTA":"a48-108.smtp-out.amazonses.com"}};
payload = JSON.stringify(payload, null, 4)
payload = payload.replace(/".*:.*":/g, 'replaced');
console.log('Replaced payload:', payload);

Mind that simply using .* means "as many characters as you can match", i.e. it's eager. You can add a ? for lazy matching, as in "match as few as possible".
I suggest using /".*?:.*?":/g since this basically means "get all characters to the closest : and then the characters to the closest ":".
Using a recursive function to map the object instead of using a RegExp on the JSON version:
const data = { "eventType": "Delivery", "mail": { "timestamp": "2021-08-09T20:41:51.515Z", "source": "removed#email.com", "sourceArn": "arn:aws:ses:us-east-1:1234567890:identity/removed.com", "sendingAccountId": "1234567890", "messageId": "1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b", "destination": ["removedl#email.com"], "headersTruncated": false, "headers": [{ "name": "From", "value": "removed#email.com" }, { "name": "To", "value": "removed#email.com" }, { "name": "Subject", "value": "Test" }, { "name": "MIME-Version", "value": "1.0" }, { "name": "Content-Type", "value": "text/plain; charset=UTF-8" }, { "name": "Content-Transfer-Encoding", "value": "7bit" }], "commonHeaders": { "from": ["removed#email.com"], "to": ["removed#email.com"], "messageId": "1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b", "subject": "Test" }, "tags": { "ses:operation": ["SendEmail"], "ses:configuration-set": ["GenericLog"], "ses:source-ip": ["123.123.123.123"], "ses:from-domain": ["email.com"], "ses:caller-identity": ["user1"], "ses:outgoing-ip": ["234.234.234.234"] } }, "delivery": { "timestamp": "2021-08-09T20:41:52.880Z", "processingTimeMillis": 1365, "recipients": ["removed#email.com"], "smtpResponse": "250 2.6.0 <1123bfe-123123b12e12d2c212a-123b12c2e1123-213f312d32c123b#email.amazonses.com> [InternalId=11231247472, Hostname=CO6PR12MB5396.namprd12.prod.outlook.com] 12090 bytes in 0.214, 55.135 KB/sec Queued mail for delivery", "reportingMTA": "a48-108.smtp-out.amazonses.com" } };
function convert(obj) {
if (typeof obj !== 'object') return obj;
if (Array.isArray(obj)) return obj.map(convert);
const result = {};
for(const key in obj) {
result[key.replace(/:/g, '_')] = convert(obj[key]);
}
return result;
}
const converted = convert(data);
console.log(converted);
console.log(JSON.stringify(converted, null, 4));

Related

How to send personalized emails to multiple addresses using sendgrid in NodeJS

I have an array of email addresses and an array of passwords. I want to send each password to its corresponding email address(email at same index) in the body of email. But I don't want to use a loop. Is it possible to use substitution in the email body and then have sendgrid pick a value from the password array for each email address.
I know I can construct a personalizations object like so :
personalizations: {to: [{email: "email1"}], substitutions: {"-pwd-": "pwd1"}}
and then use -pwd- in the body of email.
But to construct this object I again have to use a loop which I don't want.
Haven't tried it out, but according to the SendGrid Docs it should be able.
The given example in the docs (for SendGrid API v3) looks the following way:
{
"personalizations": [
{
"to": [
{
"email": "john#domain.com",
"name": "John"
}
],
"subject": "Example 01",
"substitutions": {
"-name-": "John"
}
},
{
"to": [
{
"email": "jane#domain.com",
"name": "Jane"
}
],
"subject": "Example 02",
"substitutions": {
"-name-": "Jane"
}
},
{
"to": [
{
"email": "matt#domain.com",
"name": "Matt"
}
],
"subject": "Example 03",
"substitutions": {
"-name-": "Matt"
}
}
],
"from": {
"email": "sender#senddomain.com",
"name": "Sender"
},
"reply_to": {
"email": "sender#senddomain.com",
"name": "Sender"
},
"subject": "Example",
"content": [
{
"type": "text/plain",
"value": "Hello -name-,"
},
{
"type": "text/html",
"value": "Hello -name-,"
}
]
}
By using Dynamic Transactional Templates it should work the same way with handlebars.

Send some of the properties to slack from azure alerts

How can I send some of the properties from AzureMonitorMetricAlert
The full JSON looks like:
{
"schemaId":"AzureMonitorMetricAlert",
"data": {
"version":"2.0",
"properties":null,
"status":"Active",
"context": {
"timestamp":"2019-04-30T14:19:49.4987935Z",
"id":"/subscriptions/xxxxxxxx/resourceGroups/test/providers/microsoft.insights/metricAlerts/500%20response%20code",
"name":"500 response code",
"description":"",
"conditionType":"DynamicThresholdCriteria",
"severity":"3",
"condition": {
"windowSize":"PT5M",
"allOf": [
{
"alertSensitivity":null,
"failingPeriods":null,
"ignoreDataBefore":null,
"metricName":"requests/failed",
"metricNamespace":"microsoft.insights/components",
"operator":null,
"threshold":null,
"timeAggregation":"Count",
"dimensions": [
{
"name":"ResourceId",
"value":"xxxxxxxxx"
},
{
"name":"request/resultCode",
"value":"500"
}
],
"metricValue":null
}
]
},
"subscriptionId":"xxxxxxxxxxxxxxxx",
"resourceGroupName":"test",
"resourceName":"test",
"resourceType":"microsoft.insights/components",
"resourceId":"/subscriptions/xxxxxxxxxxx/resourceGroups/test/providers/microsoft.insights/components/tests",
"portalLink":"https://portal.azure.com/#resource/subscriptions/xxxxxxxx/resourceGroups/dsdsdsdsds"
}
}
}
How can I send message to the slack including text eg: "The alert for ${context.name} was sent."
I was trying with:
"actions": {
"Post_message": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['slack']['connectionId']"
}
},
"method": "post",
"path": "/chat.postMessage",
"queries": {
"channel": "CHT0EMJ3H",
"parse": "full",
"text": "tests::::::=>>>>> #{triggerBody()?['context']['name']}"
}
},
"runAfter": {},
"type": "ApiConnection"
}
}
But it doesn't work. If I use just "text": "tests::::::=>>>>> #{triggerBody()}" the full JSON is sent but it is hard to read it since it is parsed as a string.
You can't read the properties because the output of triggerbody() is a string. so you could parse the string to Json firstly then read the properties.
So you need to use the Parse Json action, the Content is the #triggerBody() and the schema click Use sample payload to generate schema and input the Json. With this action you will be able to read the properties.
I test with HTTP Request trigger and send an mail, reading the conditionType with #{body('Parse_JSON')?['data']?['context']?['conditionType']}.

Acumatica API insert data "Bad Request"

I'm trying to insert a stock item into Acumatica using the API, but I'm getting a 400 error - Bad Request. I'm using HttpClient to login, retrieve a stock item, and send the insert request. All is working except the insert request. I have tried the following url (including expand parameter):
http://localhost/AcumaticaERP/entity/Default/6.00.001/StockItem?$expand=Attributes,CrossReferences,UOMConversions,VendorDetails,WarehouseDetails
... and also the following url (without expand parameter)
http://localhost/AcumaticaERP/entity/Default/6.00.001/StockItem
I'm calling via HttpClient PutAsync, passing in the URLs mentioned above, and the data is JSON from a stock item retrieved with the API, and which doesn't exist in the current db.
client.PutAsync(insertUrl, new StringContent(data, Encoding.UTF8, "application/json")).Result;
Any ideas what I'm missing?
NEW DETAILS:
After further debugging and testing with Postman, the error from the PUT seems to be "Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1." The JSON was taken directly from a GET though, so I'm not sure what the problem could be. Below is the JSON returning an error from the PUT.
[
{
"id": "cc27ce56-6302-4f1b-97aa-49cca3ed32ea",
"rowNumber": 1,
"note": "",
"Attributes": [],
"BaseUOM": {
"value": "EA"
},
"CrossReferences": [],
"DefaultIssueLocationID": {
"value": "R1S1"
},
"DefaultReceiptLocationID": {
"value": "RECEIVING"
},
"DefaultWarehouseID": {
"value": "WHOLESALE"
},
"Description": {
"value": "tonyitem2"
},
"ImageUrl": {},
"InventoryID": {
"value": "TONYITEM2"
},
"IsAKit": {
"value": false
},
"ItemClass": {
"value": "CONSUMER 300TOYS"
},
"ItemStatus": {
"value": "Active"
},
"ItemType": {
"value": "Finished Good"
},
"LastModified": {
"value": "2018-08-03T12:09:19.907-04:00"
},
"LotSerialClass": {
"value": "NOTTRACKED"
},
"PurchaseUOM": {
"value": "EA"
},
"SalesUOM": {
"value": "EA"
},
"UOMConversions": [],
"VendorDetails": [],
"Volume": {
"value": 0
},
"WarehouseDetails": [
{
"id": "3ca5ea4c-c651-498e-8e6c-49119481982c",
"rowNumber": 1,
"note": "",
"DefaultIssueLocationID": {
"value": "R1S1"
},
"DefaultReceiptLocationID": {
"value": "RECEIVING"
},
"IsDefault": {
"value": true
},
"QtyOnHand": {
"value": 0
},
"WarehouseID": {
"value": "WHOLESALE"
},
"custom": {},
"files": []
}
],
"Weight": {
"value": 0
},
"custom": {},
"files": []
}
]
I also tried removing the brackets surrounding the JSON, and then the error is:
"No entity satisfies the condition.". Could the issue be that the ids have GUIDs, but I'm trying to do an insert? How do you indicate that the PUT is supposed to be inserting?
I finally got the PUT to insert. What finally worked was removing the wrapping braces "[" and "]" around the entire JSON; plus removing all "id", "rowNumber", "custom", and "files" fields, and all empty collections (e.g. Attributes, CrossReferences) in my JSON. I'm not sure which of these being removed resolved it and allowed me to insert, but it finally worked.
It's real unfortunate that the JSON you retrieve via GET can't be inserted via PUT without stripping all of this out first though. What a pain.

OpenAM /json/authenticate ReST api behaves differently on different servers

I am calling the OpenAM /json/authenticate api for a realm. The request details are as below. The issue is on one server the response received contains the tokenId directly and on other it gives the authId with callbacks. Both servers are exactly same with same configuration. Any help in fixing the output to get the tokenId directly would be a great help. There is limited help available on OpenAM. This has given me a couple of sleepless nights.
Method: POST
URL: http://localhost:8080/openam/json/authenticate?realm=/MYREALM
Headers:
1. Content-Type:application/json
2. X-OpenAM-Password:Wsdwe#9900
3. X-OpenAM-Username:sdf.er#dummy.com
Output on one server
{
"tokenId": "AQIC5wM2LY4SfcwB_yB8SZ5JOfJSzlbBCIb0645ky5NrwUY.*AAJTSQACMDMAAlNLADASMjExOTAwMjczNDI5Mjg0Mjc3MgACUzEAAjAy*",
"successUrl": "/openam/console"
}
Output on other server
{
"authId": "eyAidHlwIjogIkpXVCIsGHJhbGciOiAiSFMyNTYiIH0.eyAib3RrIjogImo1Y2gybnFqaGwybGhnZ250cWIzazNkMHFpIiwgInJlYWxtIjogIm89aXRzdXBwb3J0MjQ3ZGF0YXN0b3JlLG91PXNlcnZpY2VzLGRjPW9wZW5hbSxkYz1mb3JnAWEvY2ssZGM9b3JnIiwgInNlc3Npb25JZCI6ICJBUUlDNXdNMkxZNFNmY3h0UUDSFGlielFPYkJuUVUxTTNudUlab3JFdEcxX2liNC4qQUFKVFNRQUNNREVBQWxOTEFCTTRPRGcxTkRRME16STFNRFl3TXpnNE5EUTRBQUpUTVFBQSoiIH0.rWE7A_tjcsyiXpQdAXUsS6OiHi97HhXQEkYwY919ovE",
"template": "",
"stage": "IDMDataStore1",
"header": "Access Your Account",
"callbacks": [
{
"type": "NameCallback",
"output": [
{
"name": "prompt",
"value": "Email ID:"
}
],
"input": [
{
"name": "IDToken1",
"value": "sdf.er#dummy.com"
}
]
},
{
"type": "PasswordCallback",
"output": [
{
"name": "prompt",
"value": "Password:"
}
],
"input": [
{
"name": "IDToken2",
"value": ""
}
]
},
{
"type": "TextOutputCallback",
"output": [
{
"name": "message",
"value": "\n "
},
{
"name": "messageType",
"value": "0"
}
]
}
]
}
NOTE: I am using OpenAM 13.0.0

Gmail api proper way to get email message body(text or html) from Users.message resource

I am using Users.messages.get endpoint to get a gmail response which is in this format as per documentation.
What is the proper way to decode/decrypt the message body from above response?
In my case for example, the "parts" array field in response looks like this:
[
{
"partId": "0.0",
"mimeType": "text/plain",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/plain; charset=\"UTF-8\"; format=flowed; delsp=yes"
},
{
"name": "Content-Transfer-Encoding",
"value": "base64"
}
],
"body": {
"size": 1628,
"data": "R29vZ2xlIGxvZ28NCg0KSGVsbG8gQXBwcyBTY3JpcHQgdXNlciwNCg0KVGhpcyBub3RpZmljYXRpb24gaXMgdG8gYWxlcnQgeW91IG9mIGFuIHVwZGF0ZSB0byBvbmUgb3IgbW9yZSBvZiB5b3VyIEFwcHMgIA0KU2NyaXB0IHByb2plY3RzIHRoYXQgYXJlIGF0dGFjaGVkIHRvIERvY3MsIFNoZWV0cywgYW5kIEZvcm1zIGRvY3VtZW50cyB3aXRoICANCnNjcmlwdCBzaGFyaW5nIHNldHRpbmdzIHRoYXQgZGlmZmVyIGZyb20gdGhvc2Ugb2YgdGhlIGRvY3VtZW50Lg0KDQpTdGFydGluZyBvbiBvciBhZnRlciBKdWx5IDZ0aCwgMjAxNywgdGhvc2Ugc2NyaXB0IHNoYXJpbmcgc2V0dGluZ3Mgd2lsbCBiZSAgDQp1cGRhdGVkIHRvIG1hdGNoIHRob3NlIG9mIHRoZSBkb2N1bWVudHMgdG8gd2hpY2ggdGhleSdyZSBhdHRhY2hlZC4NCg0KVGhlIHNoYXJpbmcgc2V0dGluZ3MgdXBkYXRlIHNpbXBsaWZpZXMgc2hhcmluZyBzZXR0aW5ncyBmb3IgZG9jdW1lbnRzIHdpdGggIA0KYXR0YWNoZWQgQXBwcyBTY3JpcHQgcHJvamVjdHMgYnkgdHJlYXRpbmcgdGhlbSBsaWtlIGEgc2luZ2xlIGRvY3VtZW50Lg0KDQpBcyBhIHJlc3VsdCBvZiB0aGUgc2hhcmluZyBzZXR0aW5ncyB1cGRhdGUsIGFuZCBhY2NvcmRpbmcgdG8gdGhlIGRvY3VtZW50ICANCmFjY2VzcyBsZXZlbCwgc29tZSB1c2VycyBtYXk6DQoNCg0KR2FpbiBvciBsb3NlIGFjY2VzcyB0byBhZmZlY3RlZCBwcm9qZWN0cw0KQ2hhbmdlIHRoZWlyIGFjY2VzcyBsZXZlbHMgKGZvciBleGFtcGxlLCBvd25lciwgZWRpdG9yLCByZWFkZXIpDQoNClRoaXMgY2hhbmdlIHdpbGwgbm90IGFmZmVjdCBzaGFyaW5nIHNldHRpbmdzIGZvciB0aGUgZG9jdW1lbnRzLiBPbmx5ICANCnNoYXJpbmcgc2V0dGluZ3Mgb2YgYXR0YWNoZWQgQXBwcyBTY3JpcHQgcHJvamVjdHMgd2lsbCBiZSB1cGRhdGVkLg0KDQpBIENTViBmaWxlIGF0dGFjaGVkIHRvIHRoaXMgbWVzc2FnZSBsaXN0cyBhbGwgQXBwcyBTY3JpcHQgcHJvamVjdHMgd2hlcmUgIA0KeW91J3JlIHRoZSBvd25lciBhbmQgd2hvc2Ugc2hhcmluZyBzZXR0aW5ncyB3aWxsIGNoYW5nZSBhcyBhIHJlc3VsdCBvZiB0aGlzICANCm1pZ3JhdGlvbi4gUGxlYXNlIHJldmlldyB0aGVzZSBkb2N1bWVudHMgYW5kIGNvbmZpcm0gdGhhdCB0aGVpciBzaGFyaW5nICANCnNldHRpbmdzIGFyZSBhbHNvIGFwcHJvcHJpYXRlIGZvciB0aGVpciBhdHRhY2hlZCBBcHBzIFNjcmlwdCBwcm9qZWN0cy4NCg0KSWYgY2hhbmdlcyBhcmUgcmVxdWlyZWQsIGZvciBlYWNoIGRvY3VtZW50IHdoZXJlIHNldHRpbmdzIG5lZWQgdG8gYmUgIA0KY2hhbmdlZCwgdXNlIG9uZSBvZiB0aGVzZSBtZXRob2RzOg0KDQoNCkluIERvY3Mgb3IgU2hlZXRzLCBjbGljayBTaGFyZS4NCkluIEZvcm1zLCBjbGljayBBZGQgQ29sbGFib3JhdG9yLg0KSW4gR29vZ2xlIERyaXZlLCBjbGljayBTaGFyZS4NCg0KU2luY2VyZWx5LA0KDQpUaGUgQXBwcyBTY3JpcHQgVGVhbQ0KDQoNCsKpIDIwMTcgR29vZ2xlIEluYy4gMTYwMCBBbXBoaXRoZWF0cmUgUGFya3dheSwgTW91bnRhaW4gVmlldywgQ0EgOTQwNDMNCg0KWW91IGhhdmUgcmVjZWl2ZWQgdGhpcyB1cGRhdGUgYXMgYSBHIFN1aXRlIHNlcnZpY2UgYW5ub3VuY2VtZW50Lg0KDQo="
}
},
{
"partId": "0.1",
"mimeType": "text/html",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/html; charset=\"UTF-8\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 3112,
"data": "PCEtLSBUaGlzIGNvbnRhaW5zIENTUyBpbmZvLCBzdGFydHMgdGhlIGJvZHksIGFuZCBpbnNlcnRzIHRoZSBHb29nbGUgbG9nbyBoZWFkZXIgLS0-DQo8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IFJvYm90bywgQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPg0KPGRpdiBzdHlsZT0icGFkZGluZy10b3A6IDIycHg7IHBhZGRpbmctYm90dG9tOiA4cHg7IGJvcmRlci1ib3R0b20tc3R5bGU6IHNvbGlkOyBib3JkZXItYm90dG9tLWNvbG9yOiAjZGNkY2RjOyBib3JkZXItYm90dG9tLXdpZHRoOiAxcHgiIHdpZHRoPSIxMDAlIj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IFJvYm90bywgQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMwMDAwMDA7Ij48aW1nIGFsdD0iR29vZ2xlIGxvZ28iIGJvcmRlcj0iMCIgc3JjPSJodHRwOi8vd3d3LmdzdGF0aWMuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzF4L2dvb2dsZWxvZ29fY29sb3JfMTIweDQ4ZHAucG5nIiBzdHlsZT0iZGlzcGxheTogYmxvY2s7IiB0aXRsZT0iR29vZ2xlIiB3aWR0aD0iMTIwIj4gPC9zcGFuPjwvZGl2Pg0KPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBSb2JvdG8sIEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMDAwMDAwOyI-IDwhLS0gVGhpcyBpcyB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzdWJqZWN0IC0tPiA8L3NwYW4-DQoNCg0KPCEtLSBQbGVhc2UgSU5TRVJUIHRoZSByZWxldmFudCBDdXN0b21lciBDb21tIGdrbXMgc25pcHBldCAtLT4NCjxwPkhlbGxvIEFwcHMgU2NyaXB0IHVzZXIsPC9wPg0KDQo8cD5UaGlzIG5vdGlmaWNhdGlvbiBpcyB0byBhbGVydCB5b3Ugb2YgYW4gdXBkYXRlIHRvIG9uZSBvciBtb3JlIG9mIHlvdXIgQXBwcyBTY3JpcHQgcHJvamVjdHMgdGhhdCBhcmUgYXR0YWNoZWQgdG8gRG9jcywgU2hlZXRzLCBhbmQgRm9ybXMgZG9jdW1lbnRzIHdpdGggc2NyaXB0IHNoYXJpbmcgc2V0dGluZ3MgdGhhdCBkaWZmZXIgZnJvbSB0aG9zZSBvZiB0aGUgZG9jdW1lbnQuPC9wPg0KDQo8cD48c3Ryb25nPlN0YXJ0aW5nIG9uIG9yIGFmdGVyIEp1bHkgNnRoLCAyMDE3PC9zdHJvbmc-LCB0aG9zZSBzY3JpcHQgc2hhcmluZyBzZXR0aW5ncyB3aWxsIGJlIHVwZGF0ZWQgdG8gbWF0Y2ggdGhvc2Ugb2YgdGhlIGRvY3VtZW50cyB0byB3aGljaCB0aGV5JiMzOTtyZSBhdHRhY2hlZC48L3A-DQoNCjxwPlRoZSBzaGFyaW5nIHNldHRpbmdzIHVwZGF0ZSBzaW1wbGlmaWVzIHNoYXJpbmcgc2V0dGluZ3MgZm9yIGRvY3VtZW50cyB3aXRoIGF0dGFjaGVkIEFwcHMgU2NyaXB0IHByb2plY3RzIGJ5IHRyZWF0aW5nIHRoZW0gbGlrZSBhIHNpbmdsZSBkb2N1bWVudC48L3A-DQoNCjxwPkFzIGEgcmVzdWx0IG9mIHRoZSBzaGFyaW5nIHNldHRpbmdzIHVwZGF0ZSwgYW5kIGFjY29yZGluZyB0byB0aGUgZG9jdW1lbnQgYWNjZXNzIGxldmVsLCBzb21lIHVzZXJzIG1heTo8L3A-DQoNCjx1bD4NCiAgPGxpPkdhaW4gb3IgbG9zZSBhY2Nlc3MgdG8gYWZmZWN0ZWQgcHJvamVjdHM8L2xpPg0KICA8bGk-Q2hhbmdlIHRoZWlyIGFjY2VzcyBsZXZlbHMgKGZvciBleGFtcGxlLCBvd25lciwgZWRpdG9yLCByZWFkZXIpPC9saT4NCjwvdWw-DQoNCjxwPjxzdHJvbmc-VGhpcyBjaGFuZ2Ugd2lsbCBub3QgYWZmZWN0IHNoYXJpbmcgc2V0dGluZ3MgZm9yIHRoZSBkb2N1bWVudHMuIE9ubHkgc2hhcmluZyBzZXR0aW5ncyBvZiBhdHRhY2hlZCBBcHBzIFNjcmlwdCBwcm9qZWN0cyB3aWxsIGJlIHVwZGF0ZWQuPC9zdHJvbmc-PC9wPg0KDQo8cD5BIENTViBmaWxlIGF0dGFjaGVkIHRvIHRoaXMgbWVzc2FnZSBsaXN0cyBhbGwgQXBwcyBTY3JpcHQgcHJvamVjdHMgd2hlcmUgeW91JiMzOTtyZSB0aGUgb3duZXIgYW5kIHdob3NlIHNoYXJpbmcgc2V0dGluZ3Mgd2lsbCBjaGFuZ2UgYXMgYSByZXN1bHQgb2YgdGhpcyBtaWdyYXRpb24uIFBsZWFzZSByZXZpZXcgdGhlc2UgZG9jdW1lbnRzIGFuZCBjb25maXJtIHRoYXQgdGhlaXIgc2hhcmluZyBzZXR0aW5ncyBhcmUgYWxzbyBhcHByb3ByaWF0ZSBmb3IgdGhlaXIgYXR0YWNoZWQgQXBwcyBTY3JpcHQgcHJvamVjdHMuPC9wPg0KDQo8cD5JZiBjaGFuZ2VzIGFyZSByZXF1aXJlZCwgZm9yIGVhY2ggZG9jdW1lbnQgd2hlcmUgc2V0dGluZ3MgbmVlZCB0byBiZSBjaGFuZ2VkLCB1c2Ugb25lIG9mIHRoZXNlIG1ldGhvZHM6PC9wPg0KDQo8dWw-DQogIDxsaT5JbiBEb2NzIG9yIFNoZWV0cywgY2xpY2sgPHN0cm9uZz5TaGFyZTwvc3Ryb25nPi48L2xpPg0KICA8bGk-SW4gRm9ybXMsIGNsaWNrIDxzdHJvbmc-QWRkIENvbGxhYm9yYXRvcjwvc3Ryb25nPi48L2xpPg0KICA8bGk-SW4gR29vZ2xlIERyaXZlLCBjbGljayA8c3Ryb25nPlNoYXJlPC9zdHJvbmc-LjwvbGk-DQo8L3VsPg0KDQo8cD5TaW5jZXJlbHksPC9wPg0KDQo8cD5UaGUgQXBwcyBTY3JpcHQgVGVhbTwvcD4NCjwhLS0gRmluYWxseSwgaW5jbHVkZSB0aGUgc3RhbmRhcmQgZm9vdGVyLiBUaGlzIGFsc28gZW5kcyB0aGUgYm9keSAtLT4NCjwhLS0gI2luY2x1ZGUgJy9na21zaWQvNjMyOTg2MycgLS0-DQoNCjwhLS0gRmluYWxseSwgaW5jbHVkZSB0aGUgVXNlciBzdGFuZGFyZCBmb290ZXIuIFRoaXMgYWxzbyBlbmRzIHRoZSBib2R5IC0tPg0KPGRpdiBzdHlsZT0iZm9udC1zaXplOiAxMHB4OyBjb2xvcjogIzY2NjY2NjsgcGFkZGluZy10b3A6IDhweDsgYm9yZGVyLXRvcC1zdHlsZTogc29saWQ7IGJvcmRlci10b3AtY29sb3I6ICNkY2RjZGM7IGJvcmRlci10b3Atd2lkdGg6IDFweCI-DQogIDxwPsKpIDIwMTcgIEdvb2dsZSBJbmMuIDE2MDAgQW1waGl0aGVhdHJlIFBhcmt3YXksIE1vdW50YWluIFZpZXcsIENBIDk0MDQzPC9wPg0KDQogIDxwPjxpPllvdSBoYXZlIHJlY2VpdmVkIHRoaXMgdXBkYXRlIGFzIGEgRyBTdWl0ZSBzZXJ2aWNlIGFubm91bmNlbWVudC48L2k-PC9wPg0KPC9kaXY-DQo8aW1nIGhlaWdodD0iMSIgd2lkdGg9IjMiIHNyYz0iaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9hcHBzZXJ2ZS9ta3QvaW1nL2xUUERhTG1XbHg1blNpbTF6OWp3RG1vTVYzSjRvMVZfcDhjPS5naWYiPg=="
}
}
]
And in above, the body of second element(partId 0.0 with mimeType text/html) looks like this:
"body": {
"size": 3112,
"data": "PCEtLSBUaGlzIGN...<trimmed for succintness>..cDhjPS5naWYiPg=="
}
So how do I decode this data ?.
The headers are as follow for above part(partId 0.1)
"headers": [
{
"name": "Content-Type",
"value": "text/html; charset=\"UTF-8\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
]
So the content-transfer-encoding is "quote-printable"
Same encrypted/encoded result is what I get when I fetch other email messages.
Not sure how do I decode the data from the body(neither could I find anywhere in the documentation about it).
I built something to handle this like this:
public string GetBodyWithRecursion(MessagePart p, string mimeType)
{
string Body = "";
if (p.parts.Parts != null)
{
foreach (MessagePart part in p.Parts)
{
Body = $"{Body} {GetBodyWithRecursion(part, mimeType)}";
}
}
else if (p.Body.Data != null && p.Body.AttachmentId == null && p.MimeType == mimeType)
{
Body = methodToConvertFrom64Url(p.Body.Data);
}
return Body;
}
I call this first with text/html and if this is blank - then with text/plain. Incase HTML is not available and only text is.
Hope this helps,
Mike

Resources