I'm programming an outlook add-in.
I want to modify the mail before it gets sent. Therefore I have registered me for an event before the email gets sent. I can modify it but when I m trying to change the recipient of the mail (so mail.To) it gives me an error (not while my code is running but when outlook tries to sent the mail).
Error says: '...Can not resolve the receivername' (i have translated it so it is not the real error text but close to it)
Here is my code:
void Application_ItemSend(object item, ref bool cancel)
{
if (item is Outlook.MailItem mail)
{
var to = mail.To;
var body = mail.Body;
var editedBody = to + "#" + body;
mail.Body = editedBody;
mail.To = #"<another email>";
}
}
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
//Register the new event
Globals.ThisAddIn.Application.ItemSend += Application_ItemSend;
}
You are resetting all To recipients. Is that what you really want to do? Try to use MailItem.Recipients.Add (retuns Recipient object) followed by Recipient.Resolve.
You are also setting the plain text Body property wiping out all formatting. Consider using HTMLBody instead, just keep in mind that two HTML strings must be merged rather than concatenated to produce valid HTML.
You need to cancel the action by setting the cancel parameter to true and schedule re-sending operation with a new email address. A timer which fires the Tick event on the main thread can help with that task.
Also you may consider making a copy of the email, changing recipients (do any changes on the copy) and submit it. In that case you will have to differentiate such messages and skip them in the ItemSend event handler. To get that working you may use UserProperties.
Got it working:
var to = string.Empty;
mail.Recipients.ResolveAll();
foreach (Outlook.Recipient r in mail.Recipients)
{
to += r.Address + ";";
}
if (to.Length > 0)
to = to.Substring(0, to.Length - 1);
mail.Body = to + "#" + mail.Body;
//Modify receiver
mail.To = string.Empty;
Outlook.Recipient recipient = mail.Recipients.Add("<email>");
recipient.Resolve();
Related
void send_reply(Outlook.MailItem item, HashSet<string> names)
{
Outlook.MailItem eMail = item.Reply();
// want to open an email draft box for user to type in the email's content then return to the program here
eMail.Display();
foreach (string s in names)
{
eMail.To = s;
//MessageBox.Show("this is the guy we are sending to " + item.To);
eMail.Importance = Outlook.OlImportance.olImportanceHigh;
((Outlook._MailItem)eMail).Send();
}
}
Want to send a reply to a given mailitem but only to the email addresses specified in names. Issue I'm having is when I call eMail.Display() it only shows for like half a second at most then the draft auto closes and I send a blank reply email to everyone in names.
Anyone have any suggestions?
The Display() function returns immediately and makes your message to be sent empty.
You can wait by passing true to the function:
//...
Outlook.MailItem eMail = item.Reply();
eMail.Display(true); // <-- here
//...
This will make the window Modal and will wait for user to close it.
Maybe you have also to check if the user closed it without a text inside or have the intention to undo the operation...
To do this maybe you can check the message status or register a handler to one (or both) of Close (and Send) events.
I am using visual studio 2017 installed office development pack,want to create a plugin which responds based on incoming email.
Basically I am tying to monitor an Infra support mailbox ,which forwards the email to concerned team based on the incoming message content.
Any suggestion on how this can be done
There are several ways for implementing the required functionality:
Use rules for setting up forward rules. You can do that manually in Outlook and programmatically as well. The Outlook object model provides all the required classes for that, see How to: Create a Rule to Assign Categories to Mail Items Based on Multiple Words in the Subject for more information.
Use the NewMailEx event for handling incoming emails. The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID represented by the EntryIDCollection parameter passed to call the NameSpace.GetItemFromID method and process the item. In the event handler, you may check the email received and forward the email programmatically. The Forward method of the MailItem class executes the Forward action for an item and returns the resulting copy as a MailItem object.
Sub RemoveAttachmentBeforeForwarding()
Dim myinspector As Outlook.Inspector
Dim myItem As Outlook.MailItem
Dim myattachments As Outlook.Attachments
Set myinspector = Application.ActiveInspector
If Not TypeName(myinspector) = "Nothing" Then
Set myItem = myinspector.CurrentItem.Forward
Set myattachments = myItem.Attachments
While myattachments.Count > 0
myattachments.Remove 1
Wend
myItem.Display
myItem.Recipients.Add "Dan Wilson"
myItem.Send
Else
MsgBox "There is no active inspector."
End If
End Sub
You may find the How To: Respond to an Outlook email programmatically article helpful.
This code using a event to incoming mails to the default inbox
using Outlook = Microsoft.Office.Interop.Outlook;
public partial class ThisAddIn
{
Outlook.NameSpace outlookNameSpace;
Outlook.MAPIFolder inbox;
Outlook.Items items;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
outlookNameSpace = this.Application.GetNamespace("MAPI");
inbox = outlookNameSpace.GetDefaultFolder(
Microsoft.Office.Interop.Outlook.
OlDefaultFolders.olFolderInbox);
items = inbox.Items;
items.ItemAdd +=
new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);
}
void items_ItemAdd(object Item)
{
Outlook.MailItem mail = (Outlook.MailItem)Item;
if (Item != null)
{
Outlook.MailItem replyMail = mail.Reply();
//Do your response
mail.Send();
}
}
}
I'm developing a Visual Studio extension that adds a command to VS to compose a message in Outlook with an attachment. The attachment is simple .csv file that is also produced by the extension.
So when user fires the command, outlook opens a window with an email already composed and attachment added. The user might just click send.
Now I've been asked to add possibility to send those logs compressed with zip. I would like to compose a message with an attachment already compressed, but I don't want any temporary .zip files retained after message is sent (or cancelled). How can I achieve this?
My code that composes the message and opens Outlook window:
using Microsoft.Office.Interop.Outlook;
...
private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
{
try
{
Application app = new Application();
MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
mailItem.Subject = subject;
mailItem.To = toAddr;
mailItem.Body = body;
if (logPath != null) mailItem.Attachments.Add(logPath);
mailItem.Importance = OlImportance.olImportanceNormal;
mailItem.Display(false);
return true;
}
catch (System.Exception e)
{
return false;
}
}
update
Once the email is composed, an outlook window with a composed message is displayed (it has the attachment already set). Now, the user might just send it, cancel it or whatever. He might even leave the window opened for hours (although this is not common) and then send it (even after VS has been closed). Again, i don't want any temporary archives to exist on the disk after the message is sent or cancelled.
I added full method that sends the email. It's not much more, but this method is just invoked when user selects a new Visual Studio command that my extension adds to it (tools -> send TFS logs -> from this month). There just an additional method between button handler and it simply sets some parameters for the one presented here (sets the subject, logPath and so on...)
If it's not possible, then I can also accept such an answer.
You can compress a file using this:
public static void Compress(FileInfo fileToCompress, string compressedFileName)
{
using (FileStream originalFileStream = fileToCompress.OpenRead())
{
using (FileStream compressedFileStream = File.Create(compressedFileName)
{
using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
{
originalFileStream.CopyTo(compressionStream);
}
}
}
}
Modified from: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx
For deleting the file afterwards you can attach to the MailItem.Unload Event.
This event occurs after the Close event for the Outlook item occurs,
but before the Outlook item is unloaded from memory, allowing an
add-in to release any resources related to the object. Although the
event occurs before the Outlook item is unloaded from memory, this
event cannot be canceled.
Source: http://msdn.microsoft.com/en-us/library/office/ff868564(v=office.15).aspx
Then you TrySendMethod1 could look like this
private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
{
try
{
Application app = new Application();
MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
mailItem.Subject = subject;
mailItem.To = toAddr;
mailItem.Body = body;
string compressedFileName = logpath + ".gz";
CompressedStack(logpath, compressedFileName);
if (logPath != null) mailItem.Attachments.Add( compressedFileName );
mailItem.Importance = OlImportance.olImportanceNormal;
mailItem.Display(false);
mailItem.Unload += (e) => {File.Delete(compressedFileName);};
return true;
}
catch (System.Exception e)
{
return false;
}
}
Exception handling for the File.Delete is missing, and I am not sure 100% certaing about the signature of the Unload event, but have a try and let us know.
This will NOT handle the case where Visual Studio is closed BEFORE the mail is sent! (I think that might not even be possible.)
I am setting the property (for making them As Read and with High Importance) of the mail those are coming to the MS Outlook 2010 inbox using below code -
Microsoft.Office.Interop.Outlook.Application myApp = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Microsoft.Office.Interop.Outlook.MAPIFolder myInbox = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
int i = myInbox.Items.Count;
((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i]).UnRead = false;
((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i]).Importance = OlImportance.olImportanceHigh;
This works fine when only one mail comes at a time (I can see the mail as Read and with High Importance) after the code execution but when three or four mails coming at a time then it set the property of only one mail not for all the three or four mails.
Please suggest.
Remember to save the message after setting any property.
Most importantly, your code uses multiple dot notation - for each ".", you get back a brand new COM object, so you end up setting Importance property on an object different from the one used to set the UnRead property.
int i = myInbox.Items.Count;
MailItem msg = (Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i];
msg.UnRead = false;
msg.Importance = OlImportance.
msg.Save();
Another problem is that you assume that the last item in the Items collection is the latest one. This is not generally true. As cremor suggested, use Items.ItemAdd event, but still do not forget to save the message.
You can use the ItemAdd event of the Items property of the folder:
Items inboxItems = myInbox.Items;
inboxItems.ItemAdd += HandleItemAdded;
private void HandleItemAdded(object item)
{
MailItem mail = item as MailItem;
if (mail == null) { return; }
mail.UnRead = false;
mail.Importance = OlImportance.olImportanceHigh;
}
When sending an e-mail using Microsoft Outlook I want to be able to send a hyperlink of file locations and websites in the body of the e-mail the body in my code is oMsg.Body. Any help would be greatly appreciated.
private void button13_Click(object sender, EventArgs e)
{
//Send Routing and Drawing to Dan
// Create the Outlook application by using inline initialization.
Outlook.Application oApp = new Outlook.Application();
//Create the new message by using the simplest approach.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
//Add a recipient
Outlook.Recipient oRecip = (Outlook.Recipient)oMsg.Recipients.Add("email-address here");
oRecip.Resolve();
//Set the basic properties.
oMsg.Subject = textBox1.Text + " Job Release";
oMsg.Body = textBox1.Text + " is ready for release attached is the Print and Routing";
//Send the message. 6
oMsg.Send();
//Explicitly release objects.
oRecip = null;
oMsg = null;
oApp = null;
MessageBox.Show("Print and Routing Sent");
}
From MSDN, looks like you can set the BodyFormat to olFormatHTML and use the HTMLBody property:
oMsg.BodyFormat = olFormatHTML; // <-- Probably dont need this
oMsg.HTMLBody = "<HTML><BODY>Enter the message text here.</BODY></HTML>";
From the HTMLBody page, it looks like it sets the BodyFormat for you if you use the HTMLBody property, so you should be able to skip setting it.
Using HTML for the Body instead of plain text will allow you to include markup for hyperlinks:
oMsg.HTMLBody = "<html><body>";
oMsg.HTMLBody += textBox1.Text + " is ready for release attached is the Print and Routing";
oMsg.HTMLBody += "<p><a href='http://website.com'>Web Site</a></p></body></html>";
EDIT: Changed Body property to HTMLBody property.