Outlook rule that applies only to original message - outlook

I have a rule that searches through a body message and looks for a phrase. If the phrase is found the message is categorized. Works fine except I need the rule to only categorize the original message and not any messages that are replies to that message.
Is this possible via rules?

No, a rule can't recognize whether a message is an original/initial one or not (the first from the conversation).
But I'd suggest using VBA macros instead. You can handle 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. Use this method with caution to minimize the impact on Outlook performance. 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. The EntryIDsCollection string contains the Entry ID that corresponds to that item.
So, you may get an instance of the MailItem object and use the MailItem.GetConversation method which obtains a Conversation object that represents the conversation to which this item belongs.
Sub DemoConversationTable()
Dim oConv As Outlook.Conversation
Dim oTable As Outlook.Table
Dim oRow As Outlook.Row
Dim oMail As Outlook.MailItem
Dim oItem As Outlook.MailItem
Const PR_STORE_ENTRYID As String = _
"https://schemas.microsoft.com/mapi/proptag/0x0FFB0102"
On Error Resume Next
' Obtain the current item for the active inspector.
Set oMail = Application.ActiveInspector.CurrentItem
If Not (oMail Is Nothing) Then
' Obtain the Conversation object.
Set oConv = oMail.GetConversation
If Not (oConv Is Nothing) Then
Set oTable = oConv.GetTable
oTable.Columns.Add (PR_STORE_ENTRYID)
Do Until oTable.EndOfTable
Set oRow = oTable.GetNextRow
' Use EntryID and StoreID to open the item.
Set oItem = Application.session.GetItemFromID( _
oRow("EntryID"), _
oRow.BinaryToString(PR_STORE_ENTRYID))
Debug.Print oItem.Subject, _
"Attachments.Count=" & oItem.Attachments.count
Loop
End If
End If
End Sub
The Conversation.GetTable method returns a Table object that contains rows that represent all items in the conversation. So, you may get the initial one.

Related

How to pass arguments to an event listener in LibreOffice Basic?

I am writing a macro to automate tasks on a spreadsheet in LibreOffice Calc.
One of those tasks is simply to add the numbers contained in a given cell range and write the total in the appropriate cell when one of these cells is edited. (The cells actually contain text: the names of different services. The program then fetches the number of hours associated with each service's name to add them all up.)
Editing such a cell triggers the Modify_modified(oEv) event listener.
The listener then calls the subroutine UpdateTotalHoursOfAgent(calendarSize, allServices, agentTopleftCell) which performs the task described above.
The problem is that arguments calendarSize and allServices, which are defined in other places in the code, are out of scope in the event listener.
I do not know how to pass those arguments to the listener.
I tried using global variables instead even though it is frowned upon, but I suspect that they reach the end of their lifetime when the main program's execution is complete, and are not available anymore when a cell is edited afterwards.
How can I pass arguments calendarSize and allServices to the UpdateTotalHoursOfAgent subroutine when Modify_modified(oEv) is triggered?
Here's part of the code used to create the event listener (found on a forum):
Private oListener, cellRange as Object
Sub AddListener
Dim sheet, cell as Object
sheet = ThisComponent.Sheets.getByIndex(0) 'get leftmost sheet
cellRange = sheet.getCellrangeByName("E4:J5")
oListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener") 'create a listener
cellRange.addModifyListener(oListener) 'register the listener
End Sub
Sub Modify_modified(oEv)
' *Compute agentTopleftCell*
REM How to obtain calendarSize and allServices from here?
UpdateTotalHoursOfAgent(calendarSize, allServices, agentTopleftCell)
End Sub
Sub Main
' *...code...*
Dim allServices As allServicesStruct
Dim calendarSize As calendarStruct
AddListener
' *...code...*
End Sub
I tried using global variables...
Probably you did not do it correctly. Here is how to set a global variable.
Private oListener, cellRange as Object
Global AllServices
Type allServicesStruct
svc As String
End Type
Sub AddListener
Dim sheet, cell as Object
sheet = ThisComponent.Sheets.getByIndex(0) 'get first sheet
cellRange = sheet.getCellrangeByName("E4:J5")
oListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")
cellRange.addModifyListener(oListener)
End Sub
Sub Modify_modified(oEv)
MsgBox AllServices.svc
End Sub
Sub Main
Dim allServicesLocal As allServicesStruct
allServicesLocal.svc = "example"
AllServices = allServicesLocal
AddListener
End Sub
Result:
This was adapted from my answer at https://stackoverflow.com/a/70405189/5100564

MailItem.SentOn on an item in inbox generates Object doesn't support this property or method

I want to know the mails with a particular word in the subject that were sent in the last 5 days. Here is the code snippet.
For Each m In objInbox.items
If InStr(1,UCase(m.subject), "LEAVE;",vbTextCompare) <> 0 and m.SentOn >= now-5 then
msgbox "There is a mail sent on"&m.SentOn
End If
Next
I get an error saying that
Object doesn't support this property or method:m.SentOn
If I remove m.SentOn >= now-5 condition from IF, it works as expected.
You need to make sure the item is really a MailItem object. In VB Script, you can either use the TypeName function (check for "MailItem"), or you can use the Class property (all OOM objects expose it). For the MailItem object, it will be 43.
Not every item in a mailbox folder is necessarily a MailItem.
Try adding a check on the object type before you run the check, like this:
For Each m In objInbox.Items
If TypeName(m) = "MailItem" Then
If InStr(1,UCase(m.subject), "LEAVE;",vbTextCompare) <> 0 and m.SentOn >= now-3 Then
msgbox "There is a mail sent on" & m.SentOn
End If
End If
Next
edit: modified to vbscript specifically rather than outlook-vba

Paste MSHTML.IHTMLElementCollection object in Reply email

"Original" is an email in Inbox and has a table with last column unfilled.
How do i paste "oElColl" in "Reply" ???
Dim Reply As Outlook.MailItem
Dim Original As Outlook.MailItem
Set Original = Application.ActiveExplorer.Selection(1)
Set Reply = Original.ReplyAll
Reply.Subject = "RE: " & Original.Subject
Reply.Display
Dim oHTML As MSHTML.HTMLDocument: Set oHTML = New MSHTML.HTMLDocument
Dim oElColl As MSHTML.IHTMLElementCollection
With oHTML
.Body.innerHTML = Original.HTMLBody
Set oElColl = .getElementsByTagName("table")
End With
' Code to fill the last column in oElColl
There is no easy 100% foolproof way to load HTML into an HTMLDocument object synchronously. I very much doubt that HTMLDocument.Body.innerHTML = Original.HTMLBody would work. You can use HTMLDocument.write, but it can hang for some HTML messages.
Try to use MailItem.GetInspector().WordEditor to retrieve the Word document object and use it instead.

ArcPad - VBscript - Autopopulate attributes

I am using the following script to grab parcel and address information from one layer to fill the attribute table of a newly created feature.
There is no returned error, but the problem I am having is that there seems to be the wrong information stuck in the memory of recordselect function. No matter where I place a point it gives the same parcel # and address. Or maybe it isn’t actually be performing the IF function properly.
Sub Address
Dim rsCurrentXY
Set rsCurrentXY = Map.Layers("Violations").records
rsCurrentXY.movelast
Dim objXYShape
Set objXYShape = rsCurrentXY.Fields.Shape
Dim pControls
Set pControls= Application.Map.selectionlayer.Forms("EDITFORM").Pages(“PAGE1”).Controls
Dim rsGrid
' Find corresponding map page to the valve point
Set rsGrid = Map.Layers("ACPA_parcels").records
rsGrid.movefirst
Do While Not rsGrid.eof
If rsGrid.fields.shape.Ispointin(objXYShape) Then
pControls("txtAddress").value = rsGrid.Fields("ADD1").Value
Exit Do
End If
rsGrid.Movenext
Loop
' Clean Up
Set rsCurrentXY = Nothing
Set objXYShape = Nothing
Set rsGrid = Nothing
End Sub
(I have another subroutine called "PIN" that would do the exact same thing.)
I have them called when their respective edit boxes in the custom form are activated by the inspector.
Thanks for the help,
Robert
Accessing the EDITFORM via Application.Map.selectionlayer.Forms("EDITFORM") will be problematic. Whenever working with controls on an EDITFORM you should using ThisEvent.Object to discover all your objects. For example, if your event handler is Page_OnLoad then ThisEvent.Object will refer to your current page. You should have code like this:
Dim pPage1
Set pPage1 = ThisEvent.Object
Dim pControls
Set pControls = pPage1.Controls

Sorting a collection in classic ASP

It's quite a simple question - how do I sort a collection?
I've got a CSV file with rows in a random order. I'd like to sort the rows according to the date in one column. Do I add the rows to a recordset? Can I sort with a Scripting.Dictionary?
I've clearly been spoilt with .NET and Linq, and now I find myself back in the land of classic asp, realising I must have known this 7 years ago, and missing generics immensely. I feel like a complete n00b.
In this case I would get help from big brother .net. It's possible to use System.Collections.Sortedlist within your ASP app and get your key value pairs sorted.
set list = server.createObject("System.Collections.Sortedlist")
with list
.add "something", "YY"
.add "something else", "XX"
end with
for i = 0 to list.count - 1
response.write(list.getKey(i) & " = " & list.getByIndex(i))
next
Btw if the following .net classes are available too:
System.Collections.Queue
System.Collections.Stack
System.Collections.ArrayList
System.Collections.SortedList
System.Collections.Hashtable
System.IO.StringWriter
System.IO.MemoryStream;
Also see: Marvels of COM .NET interop
I'd go with the RecordSet approach. Use the Text Driver. You'll need to change the directory in the connection string and the filename in the select statement. the Extended Property "HDR=Yes" specifies that there's a header row in the CSV which I suggest as it will make writing the psuedo SQL easier.
<%
Dim strConnection, conn, rs, strSQL
strConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\inetpub\wwwroot\;Extended Properties='text;HDR=Yes;FMT=Delimited';"
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open strConnection
Set rs = Server.CreateObject("ADODB.recordset")
strSQL = "SELECT * FROM test.csv order by date desc"
rs.open strSQL, conn, 3,3
WHILE NOT rs.EOF
Response.Write(rs("date") & "<br/>")
rs.MoveNext
WEND
rs.Close
Set rs = Nothing
conn.Close
Set conn = Nothing
%>
It's been a long time for me too. IIRC you don't have an option out of the box.
If I were you I'd put all the data in an array and then sort the array. I found a QuickSort implementation here: https://web.archive.org/web/20210125130007/http://www.4guysfromrolla.com/webtech/012799-3.shtml
Also look at the "Bubble Sort", works excellent with those classic asp tag cloud.
https://web.archive.org/web/20180927040044/http://www.4guysfromrolla.com:80/webtech/011001-1.shtml
A late late answer to this, but still of value.
I was working with small collections so could afford the approach where I inserted the item in the correct place on each occasion, effectively reconstructing the collection on each addition.
The VBScript class is as follows:
'Simple collection manager class.
'Performs the opration of adding/setting a collection item.
'Encapulated off here in order to delegate responsibility away from the collection class.
Class clsCollectionManager
Public Sub PopulateCollectionItem(collection, strKey, Value)
If collection.Exists(strKey) Then
If (VarType(Value) = vbObject) Then
Set collection.Item(strKey) = Value
Else
collection.Item(strKey) = Value
End If
Else
Call collection.Add(strKey, Value)
End If
End Sub
'take a collection and a new element as input parameters, an spit out a brand new collection
'with the new item iserted into the correct location by order
'This works on the assumption that the collection it is receiving is already ordered
'(which it should be if we always use this method to populate the item)
'This mutates the passed collection, so we highlight this by marking it as byref
'(this is not strictly necessary as objects are passed by reference anyway)
Public Sub AddCollectionItemInOrder(byref existingCollection, strNewKey, Value)
Dim orderedCollection: Set orderedCollection = Server.CreateObject("Scripting.Dictionary")
Dim strExistingKey
'If there is something already in our recordset then we need to add it in order.
'There is no sorting available for a collection (or an array) in VBScript. Therefore we have to do it ourself.
'First, iterate over eveything in our current collection. We have to assume that it is itself sorted.
For Each strExistingKey In existingCollection
'if the new item doesn't exist AND it occurs after the current item, then add the new item in now
'(before adding in the current item.)
If (Not orderedCollection.Exists(strNewKey)) And (strExistingKey > strNewKey) Then
Call PopulateCollectionItem(orderedCollection, strNewKey, Value)
End If
Call PopulateCollectionItem(orderedCollection, strExistingKey, existingCollection.item(strExistingKey))
Next
'Finally check to see if it still doesn't exist.
'It won't if the last place for it is at the very end, or the original collection was empty
If (Not orderedCollection.Exists(strNewKey)) Then
Call PopulateCollectionItem(orderedCollection, strNewKey, Value)
End If
Set existingCollection = orderedCollection
End Sub
End Class

Resources