Notification when outlook email arrives

Answered Notification when outlook email arrives

  • Monday, June 18, 2012 8:14 AM
     
     

    Hi,

    I've written a small script that will hopefully run a taskbar alert notification when an email arrives in my inbox.  So far all it does is searches through an inbox folder and calls the function if it finds the matching sender:

    #Function to fire up system tray notifications

    Function TaskTrayAlert email, subject, body {

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

    $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon

    $objNotifyIcon.Icon = "C:\Windows\System32\PerfCenterCpl.ico"
    $objNotifyIcon.BalloonTipIcon = "Info"
    $objNotifyIcon.BalloonTipText = "Press a button"
    $objNotifyIcon.BalloonTipTitle = "Outlook File Contents"
     
    $objNotifyIcon.Visible = $True
    $objNotifyIcon.ShowBalloonTip(20000)
    }

     

    #Code to search inbox
     $info = New-Object -ComObject Outlook.Application
     $objNamespace = $info.GetNamespace("MAPI")
     $objFolder = $objNamespace.GetDefaultFolder(6).Folders.Item("Alerts")
     $colItems = $objFolder.Items
     foreach ($item in $colItems) {
     If ($item.SenderEmailAddress -eq "Bill.Smith@newsgroup") {
     ("$($item.SenderEmailAddress) `t $($item.SentOn) `t $
     ($item.Subject)")
    TaskTrayAlert
     }
     }

    The problem I am facing is that my code loops through the complete folder each time. What I really need is for it to find all 'New' items maybe using a real-time monitor or perhaps if it was runing a scheduled task.

    I was also thinking maybe if the powershell script was called from an Outlook alert rule but if this is the case is there a way to parse the email for subject body etc add this to the alert information,

    Any help

    Thanks

All Replies

  • Monday, June 18, 2012 10:37 AM
     
     

    Hi James,

    I'm not very good in macros but I think better will be use Outlook rule "Run a script" with VBA macro.

    Something useful articles:
    http://msdn.microsoft.com/en-us/library/ee814736.aspx
    http://support.microsoft.com/kb/306108

    Or ask on Technet Outlook forum.

  • Monday, June 18, 2012 8:48 PM
     
      Has Code

    This may be more than you want, but with C# or VB you can make a plug-in that can subscribe to the new email event.  You may be able to do this in PowerShell, but I haven't done the research yet.  This would give you just the new email that arrived on that event.

    Also look at the members of $ObjFolder for something like .Items.Restrict this method will let you filter the folder content.  The sample I have in a shelved project is .Restrict("[Subject] > 'Test' AND [Subject] < 'Test~' and [complete] = False" (for a task).  the > and < accomplish a contains type evaluation.  If you can't get the Event to fire you could run this every X-mIn, and use either the range of time, or set a flag once processed, or modify the email body... move to another folder, there are a few options, I have used several myself.

    'http://msdn.microsoft.com/en-us/library/cc668191.aspx - Getting Started and uninstall
    ' http://msdn.microsoft.com/en-us/library/bb386179.aspx - How to Deploy 
    ' http://msdn.microsoft.com/en-us/library/bb623114(v=office.12).aspx - App Domain
    ' http://msdn.microsoft.com/en-us/library/bb296010.aspx - Create Custom Task Panes
    ' http://msdn.microsoft.com/en-us/library/bb157876.aspx - Office Add-in OverView
    ' http://msdn.microsoft.com/en-us/library/388t39t8.aspx

  • Tuesday, June 19, 2012 3:01 PM
     
     Proposed

    You can subscribe to the application's NewMailEx event, this fires up every time a new item is received and returns the new item's EntryID.  Next, setup the Action ScriptBlock for the event subscription; in it, place all the code you will need to check the new item against your filter (SenderEmailAddress). The Action ScriptBlock has its own execution context. You can dot-source or import a module from within the Action ScriptBlock or — as the demo code has — just include it.

    In the Action ScriptBlock, the code…

    • Retrieves the target folder
    • Retrieves the new item      through the GetItemFromID method
      • $Event.SourceArgs contains the item's ID
      • $folder.StoreID contains the target folder's ID
    • Checks the      item's SenderEmailAddress against      your criteria
      • Display the balloon tip If       same address

     

    $Action = {
      $folder = $Sender.Session.GetDefaultFolder(6).Folders.Item("Alerts")
      $item = $folder.Session.GetItemFromID($Event.SourceArgs, $folder.StoreID)
      if ($item.SenderEmailAddress -eq 'Bill.Smith@newsgroup') {
        $BalloonTipText = $item.SenderEmailAddress, $item.SentOn, $item.Subject -join "`t"
        Write-Host $BalloonTipText -BackgroundColor Yellow -ForegroundColor DarkBlue
        Add-Type -AssemblyName System.Windows.Forms
        $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
        $objNotifyIcon.Icon = "C:\Windows\System32\PerfCenterCpl.ico"
        $objNotifyIcon.BalloonTipIcon = "Info"
        $objNotifyIcon.BalloonTipText = $BalloonTipText
        $objNotifyIcon.BalloonTipTitle = "Outlook File Contents"
        $objNotifyIcon.Visible = $True
        $objNotifyIcon.ShowBalloonTip(20000)
      }
    }

    $null = Register-ObjectEvent $ol NewMailEx -SourceIdentifier MyNewEmailAlert -Action $Action

     

    The balloon tip's text may not be what you want to display but, you get the idea. The balloon tip works better — close to expected — when PowerShell's runs in Single Thread Apartment (STA).

     Note: I tested the code on Outlook 14 (2010) and should work on Outlook 12 (2007). NewEmailEx event behaves different in previous versions.

    • Proposed As Answer by King Julien Wednesday, June 20, 2012 11:11 AM
    •  
  • Tuesday, June 19, 2012 3:47 PM
     
     

    My old code showed that the returned sourceArgs can return a comma delimited list of EntryIDs.

    Can you also do $Sender.Session.GetItemFromID($Event.SourceArgs) ?

    My sample Called GetItemFromID and only passed the EntryID.  Without need to also pass an argument about the StoreID.

    You will get this event notification for all new messages even the one not in the "Alerts" folder.

    So you should also check to ensure that $Item isn't $null.

    Another thing I have done is set $item.ReminderSet = $true;$item.ReminderTime=Get-Date;$item.Save();

    Depending on how you use reminders this may be an easier way to notify the user vs. rolling your own Toast.

    Oh, and thanks zx38 for saving me some time, I had only attempted this from a Outlook Plugin the registering event is going to save me some work.

  • Tuesday, June 19, 2012 4:23 PM
     
     Proposed

    Hi Josh,

    First of all, you're welcome :)

    Good point about ReminderSet.

    You are correct, in Outlook 2003 the EntryIDCollection returns a comma delimited string. This behavior changed in Outlook 2007. That is the reason I placed a Note at the bottom of the code. Thanks fo verifying this, I have no way to test on previous versions.

    NewMailEx (2003)

    NewMailEx (2007)

    NewMailEx (2010)

    Yes, you can only pass the EntryID String to GetItemFromID. I complemented the call with the folder's StoreID to focus only in the Alerts folder. Otherwise, it would search every container.

    GetItemFromID

    $item can only be Null, if a Rule moves the item to a different container or deletes it. We get the new item's EntryID because it has been received. I have read about a limitation the NewMailEx event had,it canonly process a limited number of items if they arrive at the sane time, but I believe that limitation is irrelevant, given that it only returns one EntryID through EntryIDCollection — yes it kept the collection in its name. Unfortunately, I cannot verify it, I do not have Exchange and my Inboxes are not that busy ;)


    • Edited by zx38 Tuesday, June 19, 2012 4:31 PM
    • Proposed As Answer by King Julien Wednesday, June 20, 2012 11:11 AM
    •  
  • Tuesday, June 19, 2012 4:31 PM
     
     

    What will $item be if your new email is not in the "Alerts" folder. and your getItemFromID is searching a specific StoreID.  Your first post referenced $ol was that to be the Application object?  Or is there another place where you are filtering events only to those items where a rule has moved them to the Alerts Folder?  

    That brings up another question.  Is the NewMailEx event going to fire after a rule has moved the email to "Alerts" or will it be the same event that would trigger the outlook rule to move it?

    I didn't get past proof of concept when I was working on this type of thing before.  I must have been going off some 2003 documentation mixed in with the newer, and an array of 1 behaves the same as a single item (When using .Split(",");)

    I hadn't considered the performance implication of searching the entire OST Folder Structure.  2010 seems to have good indexing, I guess I should run some benchmarks, and actually wire up this PowerShell example and stop guessing and do some measuring.

  • Tuesday, June 19, 2012 8:50 PM
     
     Answered

    Yes, I stand corrected. When the new item is received in a delivery store other than the specified in the call to GetItemFromID, the method throws a nasty error that causes the event subscription to fail, this is very bad, thanks for asking about it Josh.

    It is, then, a much safer and the way to approach the OP's objective, to only pass the EntryID to the GetItemFromID method. A quick check to the new item's parent StoreID before checking the target SenderEmailAddress, will ensure the alert to the user happens only when the new item is received in the target delivery store.

    $ol is a reference to Outlook.Application

     

    Here a revised version of the previous code, try it and let us know how it behaved. Thanks again go to Josh for keeping me honest ;)

     

    $Action = {
      $folder = $Sender.Session.GetDefaultFolder(6).Folders.Item("Alerts")
      $item = $folder.Session.GetItemFromID($Event.SourceArgs)
      if ($item.Parent.StoreID -eq $folder.StoreID -and $item.SenderEmailAddress -eq 'Bill.Smith@newsgroup') {
        $BalloonTipText = $item.SenderEmailAddress, $item.SentOn, $item.Subject -join "`t"
        Write-Host $BalloonTipText -BackgroundColor Yellow -ForegroundColor DarkBlue
        Add-Type -AssemblyName System.Windows.Forms
        $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
        $objNotifyIcon.Icon = "C:\Windows\System32\PerfCenterCpl.ico"
        $objNotifyIcon.BalloonTipIcon = "Info"
        $objNotifyIcon.BalloonTipText = $BalloonTipText
        $objNotifyIcon.BalloonTipTitle = "Outlook File Contents"
        $objNotifyIcon.Visible = $True
        $objNotifyIcon.ShowBalloonTip(20000)
      }
    }

    $null = Register-ObjectEvent $ol NewMailEx -SourceIdentifier MyNewEmailAlert -Action $Action

  • Wednesday, October 24, 2012 3:12 PM
     
      Has Code

    I'm a newbie to Powershell, so forgive me if this is obvious, but when I try to run the above I get the error 'Register-ObjectEvent : Cannot register for event. An event with name 'NewMailEx' does not exist.'. If I do $ol | Get-Member it doesn't show NewMailEx or any events at all. Where are my Outlook events?

    C:\Scripts (219)> $ol = New-Object -ComObject Outlook.Application
    C:\Scripts (219)> $ol | Get-Member -MemberType Event
    C:\Scripts (219)> $null = Register-ObjectEvent $ol NewMailEx -SourceIdentifier MyNewEmailAlert -Action $Action
    Register-ObjectEvent : Cannot register for event. An event with name 'NewMailEx' does not exist.

  • Friday, October 26, 2012 3:00 PM
     
     
    Does your Get-Member Show NewMailEx on the list?  What version of outlook are you running off?  I have used this under 2010.  Not sure if I had under an earlier one or not.
  • Monday, November 05, 2012 9:44 AM
     
     

    Hi,  Can anyone tell me why this doesn't seem to work?

     $ol = New-Object -ComObject Outlook.Application

    $Action = {
       $folder = $ol.Session.GetDefaultFolder(6).Folders.Item("Inbox")
     
       $item = $folder.Session.GetItemFromID($Event.SourceArgs)
     
       if ($item.Parent.StoreID -eq $folder.StoreID -and $item.SenderEmailAddress -eq 'bennettj@rsc.org') {
     
         #$BalloonTipText = $item.SenderEmailAddress, $item.SentOn, $item.Subject -join "`t"
         $BalloonTipText = "james Bennett"
     
         Write-Host $BalloonTipText -BackgroundColor Yellow -ForegroundColor DarkBlue
     
         Add-Type -AssemblyName System.Windows.Forms
     
         $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
     
         $objNotifyIcon.Icon = "C:\Windows\System32\PerfCenterCpl.ico"
     
         $objNotifyIcon.BalloonTipIcon = "Info"
     
         $objNotifyIcon.BalloonTipText = $BalloonTipText
     
         $objNotifyIcon.BalloonTipTitle = "Email Alert"
     
         $objNotifyIcon.Visible = $True
     
         $objNotifyIcon.ShowBalloonTip(20000)
     
       }
     
    }
     
     
     
    $null = Register-ObjectEvent $ol NewMailEx -SourceIdentifier MyNewEmailAlert -Action $Action


    Alter De Ruine

  • Monday, November 05, 2012 2:01 PM
     
     

    $folder = $ol.Session.GetDefaultFolder(6

    Points to my Inbox.  The above code was pointing to an "Alerts" folder inside the inbox.

    The rest, in issolation seems to look good.

    What specificly is happening for you.

    - Josh

  • Tuesday, November 06, 2012 7:42 AM
     
     

    Hi Josh,

    It doesnt seem to fire when an email arrives.  My code seems to point to the inbox but its def not working

    james


    Alter De Ruine

  • Tuesday, November 06, 2012 2:06 PM
     
     

    I am having some luck, but I am getting my PC confused with all these registered events.

    The issue is something with the if ($item.Parent.StoreID -eq $folder.StoreID -and $item.SenderEmailAddress -eq 'eod@trintech.com') Statement.

    Write-Host is not going to work inside the Action and neither are any breakpoints, because PS is registering the event and taking its hands off of it.

    What I was able to do was move the $objNotifyIcon out of the IF and send variables to the BalloonTipText for debugging.

    $objNotifyIcon.BalloonTipText = ($sender,$Event)

    Maybe this will help pin down the issue, I think you may want to reference $sender instead of $ol.

    Let me know if that helps.


    • Edited by Josh Miller 76 Tuesday, November 06, 2012 3:11 PM Typos
    •