I am trying to embed an Excel file into an Outlook email message. I am setting the attachment type to "OlAttachmentType.olOLE", however when the message is created, the Excel document arrives as an attachment.
Below is my code. It seems pretty straightforward, but it does not work as expected.
var application = new Microsoft.Office.Interop.Outlook.Application();
var message = (MailItem)application.CreateItem(OlItemType.olMailItem);
var path = #"C:\Excel\Workbook.xlsx";
var missing = System.Type.Missing;
message.Attachments.Add(path, OlAttachmentType.olOLE, 1, missing);
message.SaveAs(#"C:\Excel\Workbook.msg", OlSaveAsType.olMSG);
application.Quit();
Outlook Object Model would not let you insert embedded OLE objects - the best you can do is access existing ones. Inserting OLE attachments is non-trivial even on the Extended MAPI level - you will need to create a specially formatted IStorage for the attachment, then populate its data in the format that only the host that will handle it later can understand. You will also need to provide the bitmap with the preview and insert the appropriate placeholder in the RTF body.
Related
I am programmatically trying to get the attachment data in C# in following way :--
Microsoft.Office.Interop.Outlook.Attachment attachment = objMail.Attachments[attachmentIndex];
if (attachment.DisplayName.Equals("Test"))
{
const string PR_ATTACH_DATA = "http://schemas.microsoft.com/mapi/proptag/0x37010102";
byte[] attachmentData = attachment.PropertyAccessor.GetProperty(PR_ATTACH_DATA);
}
Now my code is working fine if attachment is text file or image file. But if attachment is itself a mail, it throws the exception that property is unknown or can not be found.
Please suggest in which cases / type of attachments, this property "http://schemas.microsoft.com/mapi/proptag/0x37010102" will not work and in those cases, what would be alternative property / method to get the attachment data in byte array ?
Thanks
PR_ATTACH_DATA_BIN is only present for the regular by-value attachments (PR_ATTACH_METHOD == ATTACH_BY_VALUE). Embedded message or OLE attachments do not expose that property - they use PR_ATTACH_DATA_OBJ which must be opened using IAttach::OpenProperty(IID_IStorage, ...) - take a look at the existing messages using OutlookSpy - I am its author - select the message, click IMessage button, go to GetAttachmentTable tab, double click on the attachment.
Also keep in mind that PropertyAccessor.GetProperty would only be able to retrieve that property for small attachments. For large attachments, PR_ATTACH_DATA_BIN must be opened as IStream using IAttach::OpenProperty(IID_IStorage, ...) - PropertyAccessor.GetProperty does not do that. You will need to use Extended MAPI (C++ or Delphi) or Redemption (I am its author) - it exposes RDOAttachment.AsArray / AsText / AsStream properties.
Microsoft Graph Rest API is an single end point and wrapper for most Microsoft Data including events, most office products including outlook. Best of all any language can make a request to the endpoint and retrieve the information. See the complete Docs HERE to get started.
See below code for a simple Get request for outlook attachments. Note there are other more complex implementations. Docs: https://learn.microsoft.com/en-us/graph/api/attachment-get?view=graph-rest-1.0&tabs=http Scroll through the link and you can find C#, Java, and JavaScript examples on how to implement this.
GET /me/messages/{id}/attachments/{id}
GET /users/{id | userPrincipalName}/messages/{id}/attachments/{id}
GET /me/messages/{id}/attachments/{id}/$value
GET /users/{id | userPrincipalName}/messages/{id}/attachments/{id}/$value
There are a few Stackoverflow questions about this but none of them really offer a solution.
The Scenario - I'm creating an Outlook AddIn in VS2013. The user selects emails, hits my AddIn button and the emails are sent to a webservice to be stored in a database and linked to a client. Anyone, in any location will be able to open the email to view it.
Currently I am using the MailItem.SaveAs(filePath) function, then using File.ReadAllBytes(filePath) to create a byte array that can be sent to the webservice.
I delete the file as soon as I create the byte[]:
for (int x = 0; x < Emails.Count; x++)
{
//TODO: RMc - is there a better way than saving to disk? unable to convert MailItem directly to stream...!
Guid g = Guid.NewGuid();
string filePath = "c:\\temp\\" + g.ToString() + ".msg";
Emails.ElementAt(x).SaveAs(filePath);
byte[] by = File.ReadAllBytes(filePath);
File.Delete(filePath);//no longer needed now we have byte array
//this is where I create a list of objects with all required data to send to web service
}
Writing the file to disk is slow - it creates a *.msg file that may never actually get used if no one wants to view it. So I would like to be able to save the MailItem object to a byte array directly - and then I could save that to the database and only create the *.msg file if a user requires it.
The MailItem object appears to by dynamic, and so I think this is the problem.
Can anyone offer a solution or an alternative way of achieving what I have described?
Messages in the Outlook Object Model and Extended MAPI are not streamable. You can save a message in a particular format, but it will not be an exact copy. MSG format will be the closest you can get.
Use MailItem.SaveAs(..., olMsg) to save a message as an MSG file.
Currently I just created a program which can send the .xls file, I used google smtp server so I can already sent email with that server in my program. And inside my program, based on my date, I can create .xls file with today date and time. What I want to know is this file will be used to be attachment for the email. How I can do it?
Currently my file name is DateTime.Now.ToString("yyyyMMdd_hhss") + ".xls" so I can create based on today date and time. How I can retrieve the file name to be used as email attachment?
I am assuming you are using the .NET's default Emal api found in the System.Net.Mail namespace.
You can add the file as an attachment to the System.Net.Mail.MailMessage object.
The System.Net.Mail.Attachment class accepts a constructor that can take the stream which you could have used to create the xls file. So, if you create the excel file on the fly, you'll probably already have a reference to the stream where it is written. Then you need to use the code below:
using (Stream myXlsFileStream = new MemoryStream())
{
// assumig you populate the stream like this...
WriteXlsToStream(myXlsFileStream);
myXlsFileStream.Flush();
MailMessage message = new MailMessage();
// configure mail message contents ...
using (Attachment xlsAttachment = new Attachment(
myXlsFileStream,
"FileNameToAppearInEmail.xls",
"application/xls"))
{
message.Attachments.Add(xlsAttachment);
// send the message
}
}
Please, note that the stream must not be closed, and all data should have been written to it. You may need to call myXlsFileStream.Flush() (as in above code) before adding the attachment, in order to ensure that the file is entirely written.
I'm writing a program where I can send mails (using domino.dll) from three different department mailboxes (each using its own mail server and nsf-file).
All three department mailboxes have a predefined mail signature such as
Regards
Department X
Since those can change anytime I don't want to hardcode the signature in my program but extract them from the mailbox/nsf-file instead and append it to the mail body (or something else if there are better approaches).
I've been looking around all day without finding a solution to this problem, so my question is: How is this achieved?
So far my code is similar to this:
public Boolean sendNotesMail(String messageText)
{
//Create new notes session
NotesSession _notesSession = new NotesSession();
//Initialize Notes Database to null;
NotesDatabase _notesDataBase = null;
//Initialize Notes Document to null;
NotesDocument _notesDocument = null;
string mailServer = #"Path/DDB";
string mailFile = #"Deparmentmail\number.nsf";
//required for send, since its byRef and not byVal, gets set later.
object oItemValue = null;
// Start the connection to Notes. Otherwise log the error and return false
try
{
//Initialize Notes Session
_notesSession.Initialize("");
}
catch
{
//Log
}
// Set database from the mailServer and mailFile
_notesDataBase = _notesSession.GetDatabase(mailServer, mailFile, false);
//If the database is not already open then open it.
if (!_notesDataBase.IsOpen)
{
_notesDataBase.Open();
}
//Create the notes document
_notesDocument = _notesDataBase.CreateDocument();
//Set document type
_notesDocument.ReplaceItemValue("Form", "Memo");
//sent notes memo fields (To and Subject)
_notesDocument.ReplaceItemValue("SendTo", emailAddress);
_notesDocument.ReplaceItemValue("Subject", subjectText);
// Needed in order to send from a departmental mailbox
_notesDocument.ReplaceItemValue("Principal", _notesDataBase.Title);
//Set the body of the email. This allows you to use the appendtext
NotesRichTextItem _richTextItem = _notesDocument.CreateRichTextItem("Body");
// Insert the text to the body
_richTextItem.AppendText(messageText);
try
{
_notesDocument.Send(false, ref oItemValue);
}
}
EDIT:
Thanks to Richard Schwartz my solution is:
object signature = _notesDataBase.GetProfileDocument("calendarprofile", "").GetItemValue("Signature");
String[] stringArray = ((IEnumerable)signature).Cast<object>().Select(x => x.ToString()).ToArray();
_richTextItem.AppendText(stringArray[0]);
The signature is stored in a profile document in the NSF file. You can use the method NotesDatabase.getProfileDocument() to access it. This method takes two arguments:
ProfileName: The profile document name that you need to find the signature is "calendarprofile". (Yes, that's right. It's actually a common profile for many functions, but the calendar developers got there first and named it. ;-))
UniqueKey: Leave this as an empty string. (It is traditionally used to store a username in profile documents in shared databases, but not used in the calendarprofile doc in the mail file.)
You access data in the profile document the same way that you access them in regular documents, e.g., using getItem(), getItemValue(), etc. For a simple text signature, the NotesItem that you are looking for is called "Signature". I notice, however, that there are also items called "Signature_1" and "Signature_2", and "SignatureOption".
If you look at the Preferences UI for setting signatures in Notes mail, you will see that there is a choice between simple text and HTML or graphic files. No doubt this choice will be reflected in the SignatureOption item, so you will probably want to check that first. I have not explored where the data goes if you use imported HTML or graphic files, so I can't say for sure whether it goes into Signature, Signature_1, Signature_2, or somewhere else. But you can explore that on your own by using NotesPeek. You can download it here. It presents a tree-style view of the NSF file. There's a branch of the tree for Profiles, and you can find the calendarprofile there. Then just play around with different settings in the Notes mail preferences and see what changes. (NotesPeek doesn't pick up changes on the fly. You have to close and re-open the profile in NotesPeek after saving changes in the Notes mail preferences dialog in order to see the changes.)
If this gets too difficult, and you want a standard solution for all mails, you might consider this product or a similar one.
I've been tasked with writing a outlook .MSG files from XML files that have associated metadata. I've tried using the Aspose library, but all of the exposed MapiMessage properties are read only. Using the Outlook Object Model I'm unable to change the creation date, and other properties that I must have access to. I've also tried the Rebex library also, but it exports to EML, and doesn't support RTF.
My question is, is there a Mapi or any kind of way to write a .MSG file and have access over every property?
Take a look at http://www.dimastr.com/redemption/
Not positive, but it sounds like it can do what you need
Aspose now supports creating new msg files. Please check out http://www.aspose.com/documentation/utility-components/aspose.network-for-.net/creatingsaving-outlook-message-msg-files.html for details.
However, updating existing msg files is not supported currently. If you load an msg file using MapiMessage class, the properties will still be readonly.
Try to use RDOSession.CreateMessageFromMsgFile in Redemption (I am its author). You will get back RDOMail object; all you will need to do is set all the properties and call RDOMail.Save.
Something along the lines of
Redemption.RDOSession Session = new RDOSession();
Redemption.RDOMail Msg = Session.CreateMessageFromMsgFile(#"c:\temp\YourMsgFile.msg");
Msg.Sent = true;
Msg.Subject = "test";
Msg.Body = "test body";
Msg.Recipients.AddEx("the user", "user#domain.demo", "SMTP", rdoMailRecipientType.olTo);
Msg.Save();