MAPI, HrQueryAllRows: Filter messages on subject - c++

I'm pretty much new to MAPI and haven't wrote much C++ Code.
Basically I want to read all emails in the inbox and filter them based on their subject text. So far I'm using the source code provided at the microsoft msdn website which basically reads all emails from the inbox. What I want now is to not get all emails but filter them on the subject, lets say: I want all emails in my Inbox with the subject title "test".
So far I figuered out that the following line of code retrieves all the mails:
hRes = HrQueryAllRows(lpContentsTable, (LPSPropTagArray) &sptCols, &sres, NULL, 0, &pRows);
The parameter &sres is from the type SRestriction.
I tried to implement a filter on 'test' in the subject:
sres.rt = RES_CONTENT;
sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING;
sres.res.resContent.ulPropTag = PR_SUBJECT;
sres.res.resContent.lpProp = &SvcProps;
SvcProps.ulPropTag = PR_SUBJECT;
SvcProps.Value.lpszA = "test";
ScvProps is from the type SPropValue.
If i execute the application then I get 0 lines returned. If I change the String test to an empty String then I get all emails.
I'm assuming i'm using the "filter" option wrong, any ideas?
Edit: When I change the FuzzyLevel to:
sres.res.resContent.ulFuzzyLevel = FL_SUBSTRING;
then I can look for subjects that contain a single character but as soon as I add a second character I get 0 rows as result. I'm pretty sure this is just some c++ stuff that I don't understand that causes all this problems ...

I figured the problem out.
Replacing
sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING;
sres.res.resContent.ulPropTag = PR_SUBJECT;
SvcProps.ulPropTag = PR_SUBJECT;
with
sres.res.resContent.ulFuzzyLevel = FL_SUBSTRING;
sres.res.resContent.ulPropTag = PR_SUBJECT_A;
SvcProps.ulPropTag = PR_SUBJECT_A;
fixed the problem.

Related

PowerBI Query WebMethod.Post returns Expression.Error: We cannot convert the value "POST" to type Function

I'm using a website that requires that their API key AND query data be submitted using Webform.Post method. I'm able to get this to work in Python, C# and I'm even able to construct and execute a cURL command which returns a usable JSON file that Excel can parse. I am also using Postman to validate my parameters and everything looks good using all these methods. However, my goal is to build a query form that I can use within Excel but I can't get past this query syntax in PowerBi Query.
For now I am doing a simple query. That query looks like this:
let
url_1 = "https://api.[SomeWebSite].com/api/v1.0/search/keyword?apiKey=blah-blah-blah",
Body_1 = {
"SearchByKeywordRequest:
{
""keyword"": ""Hex Nuts"",
""records"": 0,
""startingRecord"": 0,
""searchOptions"": Null.Type,
""searchWithYourSignUpLanguage"": Null.Type
}"
},
Source = WebMethod.Post(url_1,Body_1)
in
Source
ScreenSnip showing valid syntax
It generates the following error:
Expression.Error: We cannot convert the value "POST" to type Function.
Details:
Value=POST
Type=[Type]
ScreenSnip of Error as it appears in PowerQuery Advanced Editor
I've spend the better part of the last two days trying to find either some example using this method or documentation. The Microsoft documentation simple states the follow:
WebMethod.Post
04/15/2018
2 minutes to read
About
Specifies the POST method for HTTP.
https://learn.microsoft.com/en-us/powerquery-m/webmethod-post
This is of no help and the only posts I have found so far criticize the poster for not using GET versus POST. I would do this but it is NOT supported by the website I'm using. If someone could just please either point me to a document which explains what I am doing wrong or suggest a solution, I would be grateful.
WebMethod.Post is not a function. It is a constant text value "POST". You can send POST request with either Web.Contents or WebAction.Request function.
A simple example that posts JSON and receives JSON:
let
url = "https://example.com/api/v1.0/some-resource-path",
headers = [#"Content-Type" = "application/json"],
body = Json.FromValue([Foo = 123]),
source = Json.Document(Web.Contents(url, [Headers = headers, Content = body])),
...
Added Nov 14, 19
Request body needs to be a binary type, and included as Content field of the second parameter of Web.Contents function.
You can construct a binary JSON value using Json.FromValue function. Conversely, you can convert a binary JSON value to a corresponding M type using Json.Document function.
Note {} is list type in M language, which is similar to JSON array. [] is record type, which is similar to JSON object.
With that said, your query should be something like this,
let
url_1 = "https://api.[SomeWebSite].com/api/v1.0/search/keyword?apiKey=blah-blah-blah",
Body_1 = Json.FromValue([
SearchByKeywordRequest = [
keyword = "Hex Nuts",
records = 0,
startingRecord = 0,
searchOptions = null,
searchWithYourSignUpLanguage = null
]
]),
headers = [#"Content-Type" = "application/json"],
source = Json.Document(Web.Contents(url_1, [Headers = headers, Content = Body_1])),
...
References:
Web.Contents (https://learn.microsoft.com/en-us/powerquery-m/web-contents)
Json.FromValue (https://learn.microsoft.com/en-us/powerquery-m/json-fromvalue)
Json.Document (https://learn.microsoft.com/en-us/powerquery-m/json-document)

How to get Body of the email using c++ builder

I want to get the email body from my Gmail account for an email so i use this code i found it in an example for how to read emails using c++ builder pop3
the code to extract body used
TIdText *EText;
int message = SpinEdit1->Value;
MyPoP3->Retrieve(message, MyEmail);
Edit1->Text = MyEmail->Subject + " | " + MyEmail->From->Address;
Memo1->Clear();
for (int i = 0; i < MyEmail->MessageParts->Count; i++) {
Memo1->Lines->Add(MyEmail->MessageParts->Items[i]->ContentType);
EText = dynamic_cast<TIdText*>(MyEmail->MessageParts->Items[i]);
Memo1->Lines->Add(EText->Body);
}
the problem is that i got undefine symbol to TidText and what i tried is to change it from TIdText to TIdMessage, but i got that i can't convert to it.
also i tried to try this without loop or something MyEmail->Body->Text
this return empty string.
the video i got this code from it here i don't know maybe the c++ builder he use is old. now i want to know how to extract the body text from the email address.
Thanks in advance.
the problem is that i got undefine symbol to TidText
Your code is missing an #include <IdText.hpp> statement.
what i tried is to change it from TIdText to TIdMessage, but i got that i can't convert to it.
Because TIdMessage does not contain nested TIdMessage objects.
also i tried to try this without loop or something MyEmail->Body->Text this return empty string.
If your email is MIME encoded, its text is not stored in the TIdMessage::Body property, but in a nested TIdText object within the TIdMessage::MessageParts collection. You have to look at the TIdMessage::ContentType property to know what kind of structure the email contains. For instance, if the CT begins with text/, the text is in the TIdMessage::Body. But if the CT begins with multipart/, the text is somewhere in the TIdMessage::MessageParts instead.
You should read this blog article on Indy's website for an example of how emails might be structured:
HTML Messages
the video i got this code from it here i don't know maybe the c++ builder he use is old.
No, it is not.

GetHostedProfilePage not honouring hostedProfileBillingAddressOptions setting

I've been trying to update our API call to the CIM interface for Authorize.net to hide the Billing Address fields on the hosted profile page.
The documentation states that when call the token creation function, passing in a setting "hostedProfileBillingAddressOptions" with a value of "showNone" will hide the billing address part of the form, however when I pass in this setting I am still getting the billing address showing.
I've verified that I'm passing the setting correctly (added the same way as the "hostedProfileIFrameCommunicatorUrl" and "hostedProfilePageBorderVisible" settings) and if I pass an invalid value for the "hostedProfileBillingAddressOptions" option, the Token creation function will return an error
Is there something else that this option is dependent on, such as an account setting or another settings parameter?
For reference, I'm testing this in the Sandbox system and I'm using the dotNet SDK, my test code for calling the API function is as follows
Public Shared Function CreateHostFormToken(apiId As String, apiKey As String, branchId As Int64, nUser As Contact, iframeComURL As String) As String
Dim nCustProfile = GetCustomerProfile(apiId, apiKey, branchId, nUser)
Dim nHost = New AuthorizeNet.Api.Contracts.V1.getHostedProfilePageRequest()
nHost.customerProfileId = nCustProfile
' Set Auth
Dim nAuth = New Api.Contracts.V1.merchantAuthenticationType()
nAuth.ItemElementName = Api.Contracts.V1.ItemChoiceType.transactionKey
nAuth.name = apiId
nAuth.Item = apiKey
nHost.merchantAuthentication = nAuth
' Set Params
Dim settingList As New List(Of Api.Contracts.V1.settingType)
Dim nParam As New Api.Contracts.V1.settingType With {.settingName = "hostedProfileIFrameCommunicatorUrl",
.settingValue = iframeComURL}
settingList.Add(nParam)
nParam = New Api.Contracts.V1.settingType With {.settingName = "hostedProfilePageBorderVisible",
.settingValue = "false"}
settingList.Add(nParam)
nParam = New Api.Contracts.V1.settingType With {.settingName = "hostedProfileBillingAddressOptions",
.settingValue = "showNone"}
settingList.Add(nParam)
nHost.hostedProfileSettings = settingList.ToArray
Dim nX = New AuthorizeNet.Api.Controllers.getHostedProfilePageController(nHost)
Dim nRes = nX.ExecuteWithApiResponse(GetEnvironment())
Return nRes.token
End Function
I've looked through the SDK code as well, and I don't see anything there that would be preventing the setting from being passed through.
Has anyone come across this issue, or successfully set the card entry form to hide the billing address?
There turned out to be two parts to the solution to this problem:
In order to use the "hostedProfileBillingAddressOptions" option, you need to use a newer version of the capture page than I was using. I was using "https://secure2.authorize.net/profile/", while the new version is "https://secure2.authorize.net/customer/". Added bonus, the new URL provides a much nicer and modern looking form.
However, once this was working, I then had the problem that on entering the card, a validation message told me that "address and Zip code are required", despite not being visible. I did also make sure that I had the option "hostedProfileBillingAddressRequired" set to false (which is it's default value anyway)
The response from Authorize.net support is that in order to capture card without an address, the option "hostedProfileValidationMode" must be set to "testMode".
This is not mentioned in the documentation (at least as far as I could see), so may not be something that other people are aware of since it is a little counter-intuitive to use 'testMode' on a live environment.
It's not ideal since validating the card for a customer account will send a transaction email to the merchant, but it seems there is not another way around this just now.
In summary, to allow the customer to add a credit card to their profile without having to provide an address, you need to specify the following options:
Form URL for capture - https://secure2.authorize.net/customer/
getHostedProfilePageRequest -
hostedProfileIFrameCommunicatorUrl: *your URL*
hostedProfilePageBorderVisible: false //assuming you are using an iFrame
hostedProfileValidationMode: testMode
hostedProfileBillingAddressOptions: showNone

EXM subscribe to list C#

I'm working on converting my old Sitecore (< 8) code to work with Sitecore EXM. I'm having a hard time adding users to Recipient Lists from code. The answers in this post: Sitecore 8 EXM add a contact to list from listmanager don't answer my questions completely, and since I cannot comment, I've decided to start a new topic.
My first problem is that my EcmFactory.GetDefaultFactory().Bl.RecipientCollectionRepository.GetEditableRecipientCollection(recipientListId) gives a compilation error on the RecipientCollectionRepository, it says it does not exist. So I've used slightly different code. My code now, is as follows:
var contactRepository = new ContactRepository();
var contactName = this.Email.Text;
var contact = contactRepository.LoadContactReadOnly(contactName);
contact = contactRepository.CreateContact(Sitecore.Data.ID.NewID);
contact.Identifiers.AuthenticationLevel = Sitecore.Analytics.Model.AuthenticationLevel.None;
contact.System.Classification = 0;
contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
contact.Identifiers.Identifier = contactName;
contact.System.OverrideClassification = 0;
contact.System.Value = 0;
contact.System.VisitCount = 0;
var contactPreferences = contact.GetFacet<IContactPreferences>("Preferences");
contactPreferences.Language = "nl-NL";
var contactEmailAddresses = contact.GetFacet<IContactEmailAddresses>("Emails");
contactEmailAddresses.Entries.Create("test").SmtpAddress = this.Email.Text;
contactEmailAddresses.Preferred = "test";
var contactPersonalInfo = contact.GetFacet<IContactPersonalInfo>("Personal");
contactPersonalInfo.FirstName = contactName;
contactPersonalInfo.Surname = "recipient";
if (recipientList != null)
{
var xdbContact = new XdbContactId(contact.ContactId);
if (!recipientList.Contains(xdbContact, true).Value)
{
recipientList.AddRecipient(xdbContact);
}
contactRepository.SaveContact(contact, new ContactSaveOptions(true, null));
}
So the recipientList is found, and the first time I add a contact to it, it increases the "Recipients" to 1 (checked using the /sitecore/system/List Manager/All Lists/E-mail Campaign Manager/Custom/RecipientList).
I also have a message which has this Opt-in recipient list, but when I check that message, it says it will be sent to 0 subscribers.
Any thoughts on this?
See this article listing known issues in Sitecore EXM:
https://kb.sitecore.net/articles/149565
"The recipient list shows "0" total recipients after recipients have been subscribed to the list. (62217)"
I got around this in a sandbox environment by adding a simple list (from csv, one contact) to the message. This upped the total recipient count from 0 to 1 which allows the message to be activated. All recipients in the composite list were sent a message.
Do you have a distributed environment? If so the RecipientCollectionRepository will not work as it is only available on a Content Management server. You could try using the ClientApi:
ClientApi.UpdateSubscriptions(RecipientId recipientId, string[] listsToSubscribe, string[] listsToUnsubscribe, string managerRootId, bool confirmSubscription)
and just add the id of the list you want to subscribe people to in the first string array.
Just a quick note with this option, listToUnsubscribe does not actually remove a contact from a list. You are meant to pass through the ID of the opt out list. This basically excludes them from any future emails. One draw back is that you will no longer be able to resubscribe them.
If this does not work for you you will need to create your own API between your CD server and your CM server where the CM server uses the recipientCollectionRepository to subscribe and unsubscribe

How to parse output from sse.client in Python?

I am new to Python and am trying to get my ahead around parsing SSE client code. I am using the SSE Client library. My code is very basic and follows the sample exactly. Here it is:
from sseclient import SSEClient
devID = "xxx"
AToken = "xxx"
sparkURL = 'https://api.spark.io/v1/devices/' + devID + '/events/?access_token=' + AToken
messages = SSEClient(sparkURL)
for msg in messages:
print(msg)
print(type(msg))
The code runs without a problem and I see some blank lines and SSE data coming through. Here is the sample output:
<class 'sseclient.Event'>
{"data":"0 days, 0:54:43","ttl":"60","published_at":"2015-04-09T22:43:52.084Z","coreid":"xxxx"}
<class 'sseclient.Event'>
<class 'sseclient.Event'>
{"data":"0 days, 0:55:3","ttl":"60","published_at":"2015-04-09T22:44:12.092Z","coreid":"xxx"}
<class 'sseclient.Event'>
The actual output above looks like a dictionary, but its type is "sseclient.Event". I am trying to figure out how to parse the output so I can pull out one of the fields and nothing I have tried has worked.
Sorry if this is basic questions, but can someone provide some simple guidance on how I would either convert the entire output to a dictionary or perhaps just pull out one of the fields?
Thank you in advance!
I figured this out. In case anyone else experiences the same problem, here is how I got it to work. The key was using msg.data and not just msg. I then converted the out using the JSON library and am good to go.
messages = SSEClient(sparkURL)
for msg in messages:
outputMsg = msg.data
if type(outputMsg) is not str:
outputJS = json.loads(outputMsg)
FilterName = "data"
#print( FilterName, outputJS[FilterName] )
print(outputJS[FilterName])