How to specify account for an outgoing Outlook message
In Outlook 2007-2010 you do this by specifying the MailItem.SendUsingAccount property. It can resemble this code:
using System.Runtime.InteropServices; using Outlook = Microsoft.Office.Interop.Outlook; ... void SetAccount_2007_2010(Outlook.MailItem mail, string accountName) { Outlook.NameSpace session = mail.Session; Outlook.Accounts accounts = session.Accounts; for (int i = 1; i < = accounts.Count; i++) { Outlook.Account account = accounts[i]; if (account.DisplayName.ToLower() == accountName.ToLower()) { mail.SendUsingAccount = account; Marshal.ReleaseComObject(account); break; } Marshal.ReleaseComObject(account); } Marshal.ReleaseComObject(accounts); Marshal.ReleaseComObject(session); }
Imports System.Runtime.InteropServices Imports Outlook = Microsoft.Office.Interop.Outlook ... Sub SetAccount_2007_2010(ByRef mail As Outlook.MailItem, _ ByVal accountName As String) Dim session As Outlook.NameSpace = mail.Session Dim accounts As Outlook.Accounts = session.Accounts For i As Integer = 1 To accounts.Count Dim account As Outlook.Account = accounts(i) If account.DisplayName.ToLower() = accountName.ToLower() Then mail.SendUsingAccount = account Marshal.ReleaseComObject(account) Exit For End If Marshal.ReleaseComObject(account) Next i Marshal.ReleaseComObject(accounts) Marshal.ReleaseComObject(session) End Sub
Another code sample is available in How to: Send an E-Mail Given the SMTP Address of an Account.
In Outlook 2000-2003, the Outlook object model doesn’t provide a way to set account. But in some situations you can use the workaround below. Here is the idea: since account names are available in the popup control called Accounts, you can find that control in your code, list all items (buttons) showing the account names and “click” the corresponding button programmatically. You do the “click” via CommandBarButton.Execute(). Unfortunately you cannot do this if Word is used as the default email editor because the Accounts control is implemented in the Envelope toolbar in this case and the toolbar is not accessible programmatically. You can see a code sample below. Note that you can specify an account in a composed email only; the code sample deals with this, too.
using Outlook = Microsoft.Office.Interop.Outlook; using Office = Microsoft.Office.Core using System.Runtime.InteropServices; using System.Reflection; ... private void SetAccount_2000_2002_2003(Outlook.Inspector inspector, string accountName) { if (inspector.IsWordMail()) return; // Word is the default email editor if (IsItemSent(inspector)) return; // sent or recieved email Office.CommandBars bars = inspector.CommandBars; Office.CommandBarPopup accounts = bars.FindControl(Office.MsoControlType.msoControlPopup, 31224, //the ID of the Accounts popup Type.Missing, true)//visible only as Office.CommandBarPopup; if (accounts != null) { Office.CommandBarControls accountControls = accounts.Controls; for (int i = 1; i < = accountControls.Count; i++) { Office.CommandBarButton account = accountControls[i] as Office.CommandBarButton; if (account.Caption.ToLower() == accountName.ToLower()) { account.Execute(); Marshal.ReleaseComObject(account); break; } Marshal.ReleaseComObject(account); } Marshal.ReleaseComObject(accountControls); Marshal.ReleaseComObject(accounts); } Marshal.ReleaseComObject(bars); } private static bool IsItemSent(Outlook.Inspector inspector) { object item = inspector.CurrentItem; bool isSent = Convert.ToBoolean(item.GetType().InvokeMember("Sent", BindingFlags.GetProperty, null, item, null)); Marshal.ReleaseComObject(item); return isSent; }
Imports Outlook = Microsoft.Office.Interop.Outlook; Imports Office = Microsoft.Office.Core Imports System.Runtime.InteropServices; Imports System.Reflection; ... Private Sub SetAccount_2000_2002_2003(ByRef inspector As Outlook.Inspector, _ ByVal accountName As String) If inspector.IsWordMail() Then Return ' Word is the default email editor If IsItemSent(inspector) Then Return ' sent or recieved email Dim bars As Office.CommandBars = inspector.CommandBars '31224 - the ID of the Accounts popup 'True - visible only Dim accounts As Office.CommandBarPopup = CType( _ bars.FindControl(Office.MsoControlType.msoControlPopup, _ 31224, Type.Missing, True), Office.CommandBarPopup) If accounts IsNot Nothing Then Dim accountControls As Office.CommandBarControls = _ accounts.Controls For i As Integer = 1 To accountControls.Count Dim account As Office.CommandBarButton = _ CType(accountControls(i), Office.CommandBarButton) If account.Caption.ToLower() = accountName.ToLower() Then account.Execute() Marshal.ReleaseComObject(account) Exit For End If Marshal.ReleaseComObject(account) Next Marshal.ReleaseComObject(accountControls) Marshal.ReleaseComObject(accounts) End If Marshal.ReleaseComObject(bars) End Sub Private Function IsItemSent(ByRef inspector As Outlook.Inspector) As Boolean Dim item As Object = inspector.CurrentItem Dim isSent As Boolean = _ Convert.ToBoolean(item.GetType().InvokeMember( _ "Sent", BindingFlags.GetProperty, Nothing, item, Nothing)) Marshal.ReleaseComObject(item) Return isSent End Function
Good luck!
4 Comments
The last time I looked for a lot of solutions.
I found a lot of them, but yours are clear amd with yours I am completely satisfied!
Thanks!
Thanks a lot! Works very well!
Regarding the snippet of code that loops through each Outlook.Account until it finds the account it’s looking for: I happen to use this functionality a lot and so I would like to create a function to return the Outlook.Account for a specified smtp address. What I can’t properly figure out is how to release the account comobject inside of the function that is returning it to the caller. See example of my question below in vb, but I also know C#:
Private Sub SendAnEmail()
Dim sendingAccount As Outlook.Account
sendingAccount = GetSenderAccount(“test@gmail.com”)
If Not IsNothing(sendingAccount) Then
‘Code here to send an email using the sendingAccount.
‘IS RELEASING THE COMOBJECT HERE SUFFICIENT TO RELEASE THE
‘OBJECT WHEN IT WAS ORIGINALLY REFERENCED IN
‘GetSenderAccount()”
Marshal.ReleaseComObject(sendingAccount)
End If
End Sub
Private Function GetSenderAccount(smtpAddress As String) As Outlook.Account
Dim senderAccount As Outlook.Account
Dim allSenderAccounts As Outlook.Accounts = OutlookApp.Session.Accounts
For Each senderAccount In allSenderAccounts
If senderAccount.SmtpAddress.ToLower = smtpAddress.ToLower Then
Marshal.ReleaseComObject(allSenderAccounts)
‘WHEN/WHERE DO I RELEASE THE senderAccount I’M RETURNING?
Return senderAccount
End If
Marshal.ReleaseComObject(senderAccount)
Next
Marshal.ReleaseComObject(allSenderAccounts)
Return Nothing
End Function
Hello David,
The SendAnEmail method is okay. Here’s a version of your other method:
Private Function GetAccountFromSmtpAddress(smtpAddress As String) As Outlook.Account
Dim ns As Outlook.NameSpace = OutlookApp.Session
Dim allAccounts As Outlook.Accounts = ns.Accounts
Dim anAccount As Outlook.Account = Nothing
For i As Integer = 1 To allAccounts.Count
anAccount = allAccounts.Item(i)
If anAccount.SmtpAddress.ToLower = smtpAddress.ToLower Then
Exit For
End If
Marshal.ReleaseComObject(anAccount) : anAccount = Nothing
Next
Marshal.ReleaseComObject(allAccounts)
Return anAccount ‘ this is either Nothing or a COM object that the caller must release
End Function
HTH