Is it possible to extract data from the body of an outlook email and throw it in SQL automatically? - outlook

Situation: We get audit emails every morning. The body of the email contains a table with various columns. The column labelled 'ID' is the unique key for each row. I have to copy the data from the ID column, format it in note++, and then paste it in a pre-filled query in SQL were I run it.
Question: Is it possible to automate this process? if so, where could I start? I would be nice if I could have something that either runs automatically or manually, reads the email, extracts the data from the column, formats it, and throws it in a query and executes.
Additional Details: The emails are always from the same distro, fire at the same time every day, and the table columns are static.
My skill Level: Beginner but resourceful and eager to learn, so please don't crucify me if I am not clear.

Yes, it is possible. You can develop a VBA macro or a COM add-in if you need to distribute your solution on multiple machines. Basically you are interested in handling the NewMailEx event of the Application class which is fired when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem.
After retrieving the incoming item you can process it by getting property values and adding them to the SQL Db.
You may find the Walkthrough: Create your first VSTO Add-in for Outlook article helpful.

Related

Sending unnecessary data in one query response or making multiple queries?

I have been working on a project. I always followed this idea. Don't send all the data in one call.
Here is an example,
Suppose there is an API to return all the list of students that can be added to test they need to finish.
So, on UI side every student have one button "add" which will show a pop up if the student is already assigned to take the test. Or it will show a pop up he has already finished the test.
I could join many table and send all the data in one api call while fetchig students. Or
I could send the send the students and then on "add" there is another API to make sure the above mentioned conditioned met.
Which approach is better?
Because If I send all the data in one api call, there might be only few students be assigned the test.
Checking if a student is already assigned or not should happen in the backend, not frontend, and also atomically so as to prevent duplicates - either using a database transaction or a unique constraint.
When the Add button is clicked then in any case a backend call will need to be made (to perform the actual Add). If the add failed, the backend can interpret the "unique constraint violation" database error and return a "student is already assigned" message.
For the rest of the question, the rule is simply: don't fetch more data than is required by the UI.
If the Add button is always shown regardless of whether or not the student is already added, there is no need to retrieve this information beforehand.
But it might be useful to give a visual indication of which students are already added, in that case obviously there's no choice but to retrieve and return this information to the UI.
Fortunately GraphQL is precisely the tool for this job - it makes it possible for the UI to request exactly what information is needed for a given page, without having to code each and every possible query by hand.

How to programmatically set the subject (title) of an Outlook 365 meeting from user data entered at runtime

Background
Our Training team uses an Excel worksheet to track our online training, listing the date, customer, topic, type of training, type of meeting (Teams live event or Teams meeting), presenter, and moderator. In addition to the information in the worksheet, we create an Outlook 365 meeting for each workshop. The subject (title) of the Outlook meeting takes this format: {Customer} {Topic} {Event Type} {Meeting Type} {Start}.
Goals
Replace the Excel worksheet with an Outlook 365 view in table
layout, eliminating a time-consuming and redundant step in our process.
Minimize data entry.
Do 1 and 2 in such a way that I can distribute the solution to our Training team without involving a request to systems admins or requiring our team to do any heavy lifting code- or configuration-wise.
Problem
I've tried two methods and am getting stuck at the same spot: I can't figure out how to set the meeting request subject equal to the information entered by the user.
Progress
Method 1: Outlook form or template
I modified P.2 in an appointment request in Outlook 365 to be a data entry form for the custom fields Customer, Topic, EventType, MeetingType, Presenter, and Moderator. Another custom field, TrainingEvent, is a read-only Boolean set to Yes when the appointment is created. I use this field to filter non-training events out of the new calendar view. Another custom field, EventID, has an initial value that concatenates the other fields in the order we need for the meeting subject. I saved the modified request as both a form and an Outlook template to test each method.
Both work fine, right up to the point of setting the actual meeting subject equal to the EventID. That is, when I submit the request the meeting is created and all the fields are populated with what I entered. The subject remains empty. I can't find any guidance, using VBA or otherwise, on how to populate the subject based on user entry at runtime.
Method 2: Microsoft Forms + Automate
So I tried another way: I created a form in Microsoft Forms to collect the same data, then ran it through Microsoft Automate modifying an existing template that creates an Outlook 365 event when a form is submitted. Same result: The event is created with all my entered data, but the subject remains empty.
Obviously, I could just ask our team to enter all the separate fields and also the subject, but that defeats goal #2.
What am I missing? This feels like it should be such an easy problem to solve.
I found the answer. I added the Subject field to my custom P.2 (data entry form). In the field properties on the Value tab, I changed "Property to use" from Value to Text and set the initial value to the concatenated field EventID. Voila!

Determine new record in PreWriteRecord event handler and check value of joined field

There is custom field "Lock Flag" in Account BC, namely in S_ORG_EXT_X table. This field is made available in Opportunity BC using join to above table. The join specification is as follows: Opportunity.Account Id = Account.Id. Account Id is always populated when creating new opportunity. The requirement is that for newly created records in Opportunity BC if "Lock Flag" is equal to 'Y', then we should not allow to create the record and we should show custom error message.
My initial proposal was to use a Runtime Event that is calling Data Validation Manager business service where validation rule is evaluated and error message shown. Assuming that we have to decide whether to write record or not, the logic should be placed in PreWriteRecord event handler as long as WriteRecord have row already commited to database.
The main problem was how to determine if it is new record or updated one. We have WriteRecordNew and WriteRecordUpdated runtime events but they are fired after record is actually written so it doesn't prevent user from saving record. My next approach was to use eScript: write custom code in BusComp_PreWriteRecord server script and call BC's method IsNewRecordPending to determine if it is new record, then check the flag and show error message if needed.
But unfortunately I am faced with another problem. That joined field "Lock Flag" is not populated for newly created opportunity records. Remember we are talking about BC Opportunity and field is placed in S_ORG_EXT_X table. When we create new opportunity we pick account that it belongs to. So it reproduceable: OpportunityBC.GetFieldValue("Lock Flag") returns null for newly created record and returns correct value for the records that was saved previously. For newly created opportunities we have to re-query BC to see "Lock Flag" populated. I have found several documents including Oracle's recomendation to use PreDefaultValue property if we want to display joined field value immediately after record creation. The most suitable expression that I've found was Parent: BCName.FieldName but it is not the case, because active BO is Opportunity and Opportunity BC is the primary one.
Thanks for your patience if you read up to here and finally come my questions:
Is there any way to handle PreWrite event and determine if it is new record or not, without using eScript and BC.IsNewRecordPending method?
How to get value of joined field for newly created record especially in PreWriteRecord event handler?
It is Siebel 8.1
UPDATE: I have found an answer for the first part of my question. Now it seems so simple to me that I am wondering how I haven't done it initially. Here is the solution.
Create Runtime Event triggered on PreWriteRecord. Specify call to Data Validation Manager business service.
In DVM create a ruleset and a rule where condition is
NOT(BCHasRows("Opportunity", "Opportunity", "[Id]='"+[Id]+"'", "AllView"))
That's it. We are searching for record wth the same Row Id. If it is new record there should't be anything in database yet (remember that we are in PreWriteRecord handler) and function returns FALSE. If we are updating some row then we get TRUE. Reversing result with NOT we make DVM raise an error for new records.
As for second part of my question credits goes to #RanjithR who proposed to use PickMap to populate joined field (see below). I have checked that method and it works fine at least when you have appropriate PickMap.
We Siebel developers have used scripting to correctly determine if record is new. One non scripting way you could try is to use RuntimeEvents to set a profileattribute during the BusComp NewRecord event, then check that in the PreWrite event to see if the record is new. However, there is always a chance that user might undo a record, those scenarios are tricky.
Another option, try invokine the BC Method:IsNewRecordPending from RunTime event. I havent tried this.
For the second part of the query, I think you could easily solve your problem using a PickMap.
On Opportunity BC, when your pick Account, just add one more pickmap to pick the Locked flag from Account and set it to the corresponding field on Opportunity BC. When the user picks the Account, he will also pick the lock flag, and your script will work in PreWriteRecord.
May I suggest another solution, again, I haven't tried it.
When new records are created, the field ModificationNumber will be set to 0. Every time you modify it, the ModificationNumber will increment by 1.
Set a DataValidationManager ruleset, trigger it from PreSetFieldValue event of Account field on Opportunity BC. Check for the LockFlag = Y AND (ModificationNumber IS NULL OR ModificationNumber = 0)) and throw error. DVM should throw error when new records are created.
Again, best practices say don't use the ModNumbers. You could set a ProfileAttribute to signal NewRecord, then use that attribute in the DVM. But please remember to clear the value of ProfileAttribute in WriteRecord and UndoRecord.
Let us know how it went !

Sharepoint Designer 2007 Workflows

In Sharepoint designer 2007, I am creating a workflow where I am trying to use 'collect data from a user' for multiple users. In my document library, I have a list name field. That list name field ties to a list which has between 1-15 users in the associated list. I only need to collect data from user for those users in the list that are not null/empty. I would also like to collect data from the users at the same time (parallel).
It appears you can only use parallel within one workflow step. Within one workflow step, it doesn't appear that you can set multiple conditions/actions.
What I need to do is this:
Condition 1: If variable:reviewer1 is not empty
Action 1: Collect Document Review from variable:reviewer1 (output to ...)
Condition 2: If variable:reviewer2 is not empty
Action 2: Collect Document Review from variable:reviewer2 (output to...)
Is there a way to do this that I'm missing?
Thanks!
It'll be tedious, but I'd suggest creating N steps (where N = the number of parallel tasks you want)
Each step will generally do the following:
Check if the current reviewer field is empty (if so, skip to the next step)
Create a new "Task" item in a (task) List
Send an email to the person you assigned the task to
Then you'll need to somehow stop your workflow until all of the tasks have been completed. This part gets a bit trickier, but do some searches on creating a State Machine workflow in SharePoint Designer and you'll be on the right track.
Really though, this sounds like a workflow that's too complex for SPD. Use Visual Studio or some 3rd-party workflow solution if at all possible.

MS CRM Save + Copy as new (Custom Entity)

I have a custom entity in Microsoft CRM (4.0). The user has to input records however usually they have a batch of 20+ records that are almost the same apart from 2 or 3 fields which need changing. I know I need to write some custom code to enable this functionally. However can anyone recommend any methods to do this.
Ideally there should be a button that will save and create a copy as a new entity.
My Current way of thinking is to pass all the details as part of the URL and use javascript to strip them out on the page load event. Any ideas welcome.
Thanks
Luke
I found the answer here:
http://mscrm4ever.blogspot.com/2008/06/cloning-entity-using-javascript.html
I've used it and it appears to work well.
Since there are numerous fields, but only certain fields values are different, then i am thinking to set the default value to all the fields, so that users just need to alter those values when needed.
In my approach, i will hook a javascript function on load of the form data entry screen and use XmlHttp approach/Ajax approach to hook to the custom web service to pull/retrieve the default values of each fields. Or you can set those values at the javascript function itself, but the drawback of this, it's difficult to customize later. So i will choose the approach to hook to the custom web service and retrieve those value from some application parameter entity.
Your idea of providing a "clone" button is also a great idea, which means that it will duplicate all the attributes of the previous record, into a new record, so that it will save time for data entry person to customize the different value
EDIT
Since you would enter records in batch mode, how about customizing .ASPX screen to enter records. By customizing through .ASPX screen, you can use a tab , so that users can browse through tabs, to customize the value/attribute of each record.
There will be a "save" button as well as "clone" button to clone some common attribute or value.
I would create a custom web service that would accept the entity type and the ID of the record I'm cloning. Your "Save and Clone" button would call the service, and the service would handle the details of retrieving the current record and deciding which fields to set on the new record. The service creates the record, and sends the Guid of the record back to your button, which then opens up the newly created record.
This way, you avoid the messiness of setting/getting values in JavaScript and tying which fields to set/retrieve directly to your OnLoads, as well as avoiding the possibility of query string that's too long.
The service could easily be sufficiently generalized so that all you'd have to do is add your button to any entity, and it would work, assuming you'd set up your service to handle that particular entity.
One possible downside is that since the clone record button would actually create the record, the user would be forced to delete the cloned record if they decided they didn't want to clone the record after all.

Resources