My company requires me to use Outlook for my E-mail. Outlook does virtually nothing the way I want to do it and it frustrates me greatly. (I'm not trying to start a flame war here, it must do exactly what thousands of CEO's want it to do, but I'm not a CEO.)
I would like to be able to automatically extract the thousands of E-mails and attachments currently in my Outlook account and save them in my own alternative storage format where I can easily search them and organize them the way I want. (I'm not requesting suggestions for the new format.)
Maybe some nice open source program already can do this... that would be great. Please let me know.
Otherwise, how can I obtain the message content and the attachments without going through the huge collection manually? Even if I could only get the message content and the names of the attachments, that would be sufficient. Is there documentation of the Outlook mail storage format? Is there a way to query Outlook for the data?
Maybe there is an alternative approach I haven't considered?
My preferred language to do this is C#, but I can use others if needed.
Outlook Redemption is the best thing currently to use that I have found. It will allow you to get into the messages and extract the attachments and the message bodies. i am using it now to do just that.
Here is some code I use in a class. I included the constructor and the processing function I use to save off the attachments. I cut out the code that is specific to my needs but you can get an idea of what to use here.
private RDOSession _MailSession = new RDOSession();
private RDOFolder _IncommingInbox;
private RDOFolder _ArchiveFolder;
private string _SaveAttachmentPath;
public MailBox(string Logon_Profile, string IncommingMailPath,
string ArchiveMailPath, string SaveAttPath)
{
_MailSession.Logon(Logon_Profile, null, null, true, null, null);
_IncommingInbox = _MailSession.GetFolderFromPath(IncommingMailPath);
_ArchiveFolder = _MailSession.GetFolderFromPath(ArchiveMailPath);
_SaveAttachmentPath = SaveAttPath;
}
public void ProcessMail()
{
foreach (RDOMail msg in _IncommingInbox.Items)
{
foreach (RDOAttachment attachment in msg.Attachments)
{
attachment.SaveAsFile(_SaveAttachmentPath + attachment.FileName);
}
}
if (msg.Body != null)
{
ProcessBody(msg.Body);
}
}
}
edit:
This is how I call it and what is passed
MailBox pwaMail = new MailBox("Self Email User", #"\\Mailbox - Someone\Inbox",
#"\\EMail - Incomming\Backup", #"\\SomePath");
If you want to extract your e-mails take a look at
Outlook Email Extractor
at codeproject
http://69.10.233.10/KB/dotnet/OutlookEmailExtractor.aspx
rob
www.filefriendly.com
Related
Currently I'm working on migration of one big project from MAPI CDO to EWS (Managed API 2.2) to support Ex2016. All things were migrated well except one: I can't find the way how to read\write Attachments Extended Properties. Does anybody know how to do that or may be some workaround? This is very critical for me and I would be very appreciate for any help.
---Update:
Also tried to use native EWS to get property of attachment but without success too:
var ret = esb.GetAttachment(new GetAttachmentType()
{
AttachmentIds = new []{new AttachmentIdType()
{
Id = "AAMkADVhNjUzMzMyLTRiMDYtNDc4OS1hYjJjLWI1ZDA4ZWFhYTJkZQBGAAAAAADqFaOFYZSeQI5UObwGbjIJBwAOgaos6ORVS5+o5bQovn/kAAAAeN2cAAAOgaos6ORVS5+o5bQovn/kAAAeCoIuAAABEgAQAJPAuRg2gipPmEKfgW26mFU=",
}},
AttachmentShape = new AttachmentResponseShapeType()
{
BodyType = BodyTypeResponseType.Best,
BodyTypeSpecified = true,
IncludeMimeContent = false,
IncludeMimeContentSpecified = true,
AdditionalProperties = new []
{
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x3705"},
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x0E21"},
}
}
});
The response doesn't contain any of requested properties.
--- Update 2:
In project we use next properties of attachments:
PR_RECORD_KEY, PR_DISPLAY_NAME, PR_RENDERING_POSITION
PR_ATTACH_ENCODING, PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_ATTACH_CONTENT_ID, PR_ATTACH_FLAGS, PR_ATTACH_MIME_TAG, PR_ATTACH_CONTENT_LOCATION, PR_ATTACH_SIZE
Also we create a couple of Custom Extended Properties with custom Property Set and tag some attachments with that props.
Some of Properties can be found in object model of EWS/ManagedApi like PR_ATTACH_SIZE but the problem with others and with custom props.
So we need to read/write standard attachment properties as well as custom.
In project we mark attachment itself, not embedded Item.
You can't access extended properties on Attachments or the Recipients collection in EWS outside of those properties that are made accessible as strongly typed properties by the API. The only place you can use Extended properties are at the message level.
That said can you explain more as to how your using Extended properties eg are these extended properties on embeded items. If that is the case then you could access those extended properties via the Item Attachment.
Looking at your code 0x3705 is the PR_ATTACH_METHOD property on an attachment there is no equivalent to this in EWS, rather EWS will return a different Attachment Class based on the Attachment type. Eg ItemAttachment, FileAttachment or ReferanceAttachment (eg for OneDrive Attachments). 0x0E21 is that Attachment number EWS is going to return the Attachments in the order of that number in GetItem request so you can compute that yourself. But the property is useless in EWS because to get an Attachment you need the EWSId unlike MAPI.
Cheers
Glen
I wrote an add-in for Outlook years ago that adds entries to a database based on the Item's ConversationIndex/ConversationId properties. This works great and remains uniform across all clients interacting with the messages (e.g. "Bob" can see that "Mary" already processed this message because an entry with the ConversationIndex already exists).
I'm now trying to move this piece to a service (and connect via the EWS API) but I'm not having good luck matching these properties with the values coming from Outlook. For example:
The Outlook Add-In will give me the following values for a specific email I'm targeting:
ConversationID: 6B6369F5023EA646AA7BC161274BDAE8
ConversationIndex: 0101CF3C7EEC6B6369F5023EA646AA7BC161274BDAE8
However, from the EWS API I get the following:
ConversationID: AAQkADFhZThkNmJmLTlkODItNDQyZS1hM2YxLTQ2NWNkMTllYjhjOQAQAGtjafUCPqZGqnvBYSdL2ug=
ConversationIndex: new byte[]{1,1,207,60,126,236,107,99,105,245,2,62,166,70,170,123,193,97,39,75,218,232}
I recognize the first as a Base64 encoded string, however what I get decoded doesn't look like anything I recognize (or can decipher). Is there anyone familiar with this, or who can help to get these two values to align? I can only imagine these properties come from the exchange server is some fashion, but the Client probably performs some cleansing whereas the EWS API just gives me the raw value (less the Base64 for what I presume transport purposes given the XML medium).
If anyone is familiar with this or has done it before I would greatly appreciate any guidance.
Side Note:
There are probably better ways to identify emails but for now I'm stuck with trying to keep these two synonymous. Modifying the outlook add-in isn't really an option, and once I migrate a 1:1 translation to the server (and drop the add-in) I'll have flexibility changing how it work. But for now I need them to run side-by-side. I need to be able to see processes made within Outlook from the web server and vise-versa.
Just found out (I think).
Breakdown
With more Googling and a bit more effort I believe I was able to make them align 1:1 using the following:
ConversationId
This is apparently an assembled value made up of several properties. Luckily I was able to find a method Woodman posted re-implementing the original algorithm used by Outlook here. With some minor modifications (to work with EWS instead of Outlook) I was able to get it to work.
ConversationIndex
This turned out to simply be a matter of using the BitConverter (and removing the hyphens). Easy peasy.
Final Result:
public static class EwsEmailMessageExtensions
{
private const int c_ulConvIndexIDOffset = 6;
private const int c_ulConvIndexIDLength = 16;
private static ExtendedPropertyDefinition PidTagConversationIndexTracking = new ExtendedPropertyDefinition(0x3016, MapiPropertyType.Boolean);
// HUGE props to Woodman
// https://stackoverflow.com/a/21625224/298053
public static string GetOutlookConversationId(this EmailMessage emailMessage)
{
Boolean convTracking;
if (!emailMessage.TryGetProperty(PidTagConversationIndexTracking, out convTracking))
{
convTracking = true;
}
var convIndex = emailMessage.ConversationIndex;
byte[] idBytes;
if (convTracking && convIndex != null && convIndex.Length > 0)
{
// get Id from Conversation index
idBytes = new byte[c_ulConvIndexIDLength];
Array.Copy(convIndex, c_ulConvIndexIDOffset, idBytes, 0, c_ulConvIndexIDLength);
}
else
{
// get Id from Conversation topic
var topic = emailMessage.ConversationTopic;
if (string.IsNullOrEmpty(topic))
{
return string.Empty;
}
if (topic.Length >= 265)
{
topic = topic.Substring(0, 256);
}
topic = topic.ToUpper();
using (var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider())
{
idBytes = md5.ComputeHash(Encoding.Unicode.GetBytes(topic));
}
}
return BitConverter.ToString(idBytes).Replace("-", string.Empty);
}
public static String GetOutlookConversationIndex(this EmailMessage emailMessage)
{
var convIndex = emailMessage.ConversationIndex;
return BitConverter.ToString(convIndex).Replace("-", String.Empty);
}
}
Usage:
// Prep
ExchangeService service = new ExchangeService(...);
Folder inbox = Folder.bind(service, WellKnownFolderName.Inbox);
Item item = /* inbox.FindItems(...).First() */
// Implmentation
EmailMessage emailMessage = item as EmailMessage;
if (emailMessage != null)
{
String conversationId = emailMessage.GetOutlookConversationId();
String conversationIndex = emailMessage.GetOutlookConversationIndex();
/* ... */
}
I am stuck with a issue from 5 days.
I need a way to attain following requirement.
mailing list is present in Database(SQL server)
I have a mail in Outlook
now i have to send mail to all the 200,000 mail ids in Database
**Note one mail can have only 200 mail IDs so
200,000/200=1000 mails **Note: this 200,000 count is not fixed it will decrease and increase>
like jhon#xyz.com will be present today , next day we may need not send to him
his name might be completely removed (so DL is not an option)
I need a way to automate this
All i have a sleep less nights and coffee cups on my desk
I work in ASP.net any PL which meets this need is fine.
I assume that you know how to create sql statement for what you need and how to retrieve data from database in .NET. This means that only issue is actually sending this from outlook.
Here is an article that describes this in detail and piece of code copied from there.
using System;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace OutlookAddIn1
{
class Sample
{
public static void SendEmailFromAccount(Outlook.Application application, string subject, string body, string to, string smtpAddress)
{
// Create a new MailItem and set the To, Subject, and Body properties.
Outlook.MailItem newMail = (Outlook.MailItem)application.CreateItem(Outlook.OlItemType.olMailItem);
newMail.To = to;
newMail.Subject = subject;
newMail.Body = body;
// Retrieve the account that has the specific SMTP address.
Outlook.Account account = GetAccountForEmailAddress(application, smtpAddress);
// Use this account to send the e-mail.
newMail.SendUsingAccount = account;
newMail.Send();
}
public static Outlook.Account GetAccountForEmailAddress(Outlook.Application application, string smtpAddress)
{
// Loop over the Accounts collection of the current Outlook session.
Outlook.Accounts accounts = application.Session.Accounts;
foreach (Outlook.Account account in accounts)
{
// When the e-mail address matches, return the account.
if (account.SmtpAddress == smtpAddress)
{
return account;
}
}
throw new System.Exception(string.Format("No Account with SmtpAddress: {0} exists!", smtpAddress));
}
}
}
What I would suggest is to skip using outlook unless that’s really necessary and send email by directly communicating with SMTP server.
Just search for “how to send email from C#” or something similar and you’ll find a ton of examples.
I would like to ask if there is a standard to store username and password in a Windows Phone application.
I am working on a project that validates the user on every request that is called. So, I want to store the username and password. Maybe even give them the possibility to "remember me", so if there isn't a standard for doing that, I will have to write it myself, but I'm guessing that Microsoft has a build-in one.
Use ProtectedData.
I found this example on Kevin D. Wolf's efficientcoder.net :
public static String Password {
get {
if (IsolatedStorageSettings.ApplicationSettings.Contains(STR_PASSWORÐ)) {
var bytes = IsolatedstorageSettings.Applicationsettings[STR_PASSwORÐ] as byte[];
var unEncrypteBytes = ProtectedData.Unprotect(bytes, null);
return Encoding.UTF8.GetString(unEncrypteBytes, 0, unEncrypteBytes.Length);
} else {
return string.Empty;
}
}
set {
var encryptedBytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(value), null);
IsolatedStorageSettings.ApplicationSettings[STR_PASSWORÐ] = encryptedBytes;
}
}
(Apologies for the cut and paste I had to use a text from image scan)
You should encrypt you passwords and other sensitive data using the ProtectedData class routines, and manually store them in Isolated Storage for your application.
To encrypt
To decrypt
Also, make sure you add a reference to mscorelib extended to your project. I had to learn this the hard way.
A good article on the topic is:
http://debugmode.net/2011/10/16/protecting-password-or-any-data-in-windows-phone-7-using-data-protection-api/
I'm using Umbraco 4.6.2, and need to extend the default notifications it provides. For the sake of this question, let's say I am trying to add an "Unpublish" notification.
In \umbraco\presentation\umbraco\dialogs\notifications.aspx.cs it constructs the list of checkbx items shown to the user when opening the "Notifications" dialogue from the context menu.
I see that each Action has a ShowInNotifier property - how can I set this value to true for the UnPublish action?
Does this require modifying the core codebase, or is there a nice way I can gracefully extend Umbraco?
So after I have added this, users can subscribe to the UnPublish notification (am I missing any steps here?).
Will this automagically send notifications now?
I'm guessing not, so the next thing I have done is hooked the UnPublish event:
public class CustomEvents : ApplicationBase
{
public CustomEvents()
{
Document.AfterUnPublish += new Document.UnPublishEventHandler(Document_AfterUnPublish);
}
void Document_AfterUnPublish(Document sender, umbraco.cms.businesslogic.UnPublishEventArgs e)
{
var user = User.GetCurrent();
if (!string.IsNullOrEmpty(user.Email) && user.GetNotifications(sender.Path).Contains("UnPublish"))
{
//Send a notification here using default Umbraco settings, or, construct email and send manually:
string umbracoNotificationSenderAddress = ""; //How to get the address stored in umbracoSettings.config -> <notifications> -> <email>
//How to use the same subject/message formats used for other notifications? With the links back to the content?
string subject = "Notification of UnPublish performed on " + MyUtilities.GetFriendlyName(sender.Id);
string message = MyUtilities.GetFriendlyName(sender.Id) + " has just been unpublished.";
umbraco.library.SendMail(umbracoNotificationSenderAddress, user.Email, subject, message, true);
}
}
}
So the bits of that code that are not real/I need some pointers on:
Is that the correct way for checking if a user is subscribed to a particular notification?
How can I send a notification using the default umbraco settings? (e.g. generate an email just like the other notifications)
If that is not possible and I must construct my own email:
How do I get the from email address stored in umbracoSettings.config that
How can I copy the formatting used by the default Umbraco notifications? Should I manually copy it or is there a nicer way to do this (programmatically).
Any help (or even just links to relevant examples) are appreciated :>
My colleague got this working.
Create a class that overrides the action you wish to have notifications for.
You can see all the actions in /umbraco/cms/Actions
public class ActionUnPublishOverride : umbraco.BusinessLogic.Actions.ActionUnPublish, IAction
{
... see what the other actions look like to find out what to put in here!
In the overridden class, you will have a public char Letter. Set this to match the event to hook into. You can find the letters each event has in the database.
Set the public bool ShowInNotifier to true.
That's it!
I've got this working on Umbraco 4.7 by using the UmbracoSettings class:
http://www.java2s.com/Open-Source/CSharp/Content-Management-Systems-CMS/umbraco/umbraco/businesslogic/UmbracoSettings.cs.htm
umbraco.library.SendMail(umbraco.UmbracoSettings.NotificationEmailSender, newMember.Email, "email subject", "email body", false);