I try to get the content ID's of the attachments of mails in outlook. I use Add-In Express for my Add-In, but it has no function to get it.
I know of the Redemption library, but it's not free and thus not an option for me.
In Outlook 2007+ there is the PropertyAccessor, which should me allow to do it, but I can't get it to work.
Here my code:
string uniqueId = "";
object props = a.GetType().InvokeMember("PropertyAccessor", BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty, null, a, null);
object[] args = new object[1];
args[0] = #"urn:schemas:mailheader:content-id";
object value = props.GetType().InvokeMember("GetProperty", BindingFlags.Public | BindingFlags.InvokeMethod, null, props, args);
if ((string)value != null) {
uniqueId = (string)value;
}
"a" is an attachment gotten from an Add-In Express MailItem.
It just throws the following exception: "Exception has been thrown by the target of an invocation."
Can someone help me?
I tried your URN as well and it did not work.
Using DASL, this works: http://schemas.microsoft.com/mapi/proptag/0x3712001F
Outlook Spy has a free trial period. I would download that in the meantime (which is where I found this value). And even when it expires, this valuable tool is less than Redemption itself.
Related
I am currently developing a small application in C# . Net allowing to perform different tasks, but here in one of my tasks I have to open a new default mail from Lotus. However I don’t find much documentation on it, so I’m a little lost and that’s why I’m in your hands :/
So I just need to be able to open Lotus with a new default email.
Thank in advance ;)
I suggest you use the selenium web driver to access their website and automatically create an email account.
Manipulating the application it self can be quite complex you can use the .NET windows Input Simulator Nugat package to simulate user input to the application or write directly to memory using the windows API.
I don't think there is a supported way of doing that by Lotus.
But if you can use Gmail there is a Gmail API
https://developers.google.com/gmail/api/guides/
Use the .NET httpClient to interact with it.
And to create a Gmail account
https://developers.google.com/admin-sdk/directory/v1/guides/manage-users
public void ComposeMemo(String sendto, String subject, String body)
{
//BLOC1 instantiate a Notes session and workspace
Type NotesSession = Type.GetTypeFromProgID("Notes.NotesSession");
Type NotesUIWorkspace = Type.GetTypeFromProgID("Notes.NotesUIWorkspace");
Object sess = Activator.CreateInstance(NotesSession);
Object ws = Activator.CreateInstance(NotesUIWorkspace);
//BLOC2 open current user's mail file
String mailServer = (String)NotesSession.InvokeMember("GetEnvironmentString", BindingFlags.InvokeMethod, null, sess, new Object[] { "MailServer", true });
String mailFile = (String)NotesSession.InvokeMember("GetEnvironmentString", BindingFlags.InvokeMethod, null, sess, new Object[] { "MailFile", true });
NotesUIWorkspace.InvokeMember("OpenDatabase", BindingFlags.InvokeMethod, null, ws, new Object[] { mailServer, mailFile });
Object uidb = NotesUIWorkspace.InvokeMember("GetCurrentDatabase", BindingFlags.InvokeMethod, null, ws, null);
Object db = NotesUIWorkspace.InvokeMember("Database", BindingFlags.GetProperty, null, uidb, null);
Type NotesDatabase = db.GetType();
//BLOC3 compose a new memo
Object uidoc = NotesUIWorkspace.InvokeMember("ComposeDocument", BindingFlags.InvokeMethod, null, ws, new Object[] { mailServer, mailFile, "Memo", 0, 0, true });
Type NotesUIDocument = uidoc.GetType();
NotesUIDocument.InvokeMember("FieldSetText", BindingFlags.InvokeMethod, null, uidoc, new Object[] { "EnterSendTo", sendto });
NotesUIDocument.InvokeMember("FieldSetText", BindingFlags.InvokeMethod, null, uidoc, new Object[] { "Subject", subject });
NotesUIDocument.InvokeMember("FieldSetText", BindingFlags.InvokeMethod, null, uidoc, new Object[] { "Body", body });
//BLOC4 bring the Notes window to the front
String windowTitle = (String)NotesUIDocument.InvokeMember("WindowTitle", BindingFlags.GetProperty, null, uidoc, null);
Interaction.AppActivate(windowTitle);
}
The BLOC1 perform, it open the application but from BLOC2 the application no longer responds but I don’t know why, more in BLOC4 the word Interaction is not recognized
I'm referring this thread to refresh the windows explorer, I want to refresh some windows only, which means I want to filter the opened windows according to their title or path. Let me copy the code from that thread for more clarification:
Guid CLSID_ShellApplication = new Guid("13709620-C279-11CE-A49E-444553540000");
Type shellApplicationType = Type.GetTypeFromCLSID(CLSID_ShellApplication, true);
object shellApplication = Activator.CreateInstance(shellApplicationType);
object windows = shellApplicationType.InvokeMember("Windows", System.Reflection.BindingFlags.InvokeMethod, null, shellApplication, new object[] { });
Type windowsType = windows.GetType();
object count = windowsType.InvokeMember("Count", System.Reflection.BindingFlags.GetProperty, null, windows, null);
for (int i = 0; i < (int)count; i++)
{
object item = windowsType.InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, windows, new object[] { i });
Type itemType = item.GetType();
string itemName = (string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);
if (itemName == "Windows Explorer")
{
// Here I want to check whether this window need to be refreshed
// based on the opened path in that window
// or with the title of that window
// How do I check that here
itemType.InvokeMember("Refresh", System.Reflection.BindingFlags.InvokeMethod, null, item, null);
}
}
What I understood from the above code is: By using this line windowsType.InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, windows, new object[] { i }); we will get the current window object, and then we are using .InvokeMember("Name".. to get the name of that object, like wise what should I pass to InvokeMember method to get the path of that object or the title of that window? or can anyone tell me the possible alternative values for "Name" in the above statement?
What I'm expecting is some code like the following:
string itemPath = (string)itemType.InvokeMember("Something here", System.Reflection.BindingFlags.GetProperty, null, item, null);
OR
string itemTitle = (string)itemType.InvokeMember("Something here", System.Reflection.BindingFlags.GetProperty, null, item, null);
I can give you more information if you need, expecting expert's suggestion to solve this issue,
Thanks in advance
This is the way you had to write late-bound COM client code in the Bad Old Days. Considerable pain and suffering to get it going, what is in the snippet is not close yet. I'll first propose a very different way to do this, there just isn't any point in doing it late-bound since these COM objects are available on any Windows version and are never going to change anymore. The "Embed Interop Types" feature supported since VS2010 removes any good reason to avoid it.
Project > Add Reference > COM tab. Tick "Microsoft Internet Controls" and "Microsoft Shell Controls and Automation". Now you can write it early-bound, nice and compact with all the benefits of IntelliSense to help you find the correct members and avoid typos:
var shl = new Shell32.Shell();
foreach (SHDocVw.InternetExplorer win in shl.Windows()) {
var path = win.LocationURL;
if (!path.StartsWith("file:///")) continue;
path = System.IO.Path.GetFullPath(path.Substring(8));
if (path.StartsWith("C")) win.Refresh();
}
A slightly silly example, it refreshes any Explorer window who's displayed path is located on the C drive. Note how the Path property is not useful to discover what is displayed, LocationURL is needed. You might have to find the distinction between Internet Explorer and Windows Explorer windows (aka "File Explorer"), albeit that IE can also display directory content so I think this is the most correct version.
If you really want to do this late-bound then use the dynamic keyword to minimize the suffering. In this case almost identical:
dynamic shl = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
foreach (var win in shl.Windows()) {
string path = win.LocationURL;
if (!path.StartsWith("file:///")) continue;
path = System.IO.Path.GetFullPath(path.Substring(8));
if (path.StartsWith("C")) win.Refresh();
}
Answering your question explicitly, use "LocationURL".
I'm currently looking at serializing a MailMessage object in C# and although there are a couple of variations of an example on the net, they serialize to binary which kind of misses the point IMO.
My approach is that I'd like to serialize a MailMessage to an RFC2822 eml string and the code below is what I've come up with.
public string SerializeEmail(MailMessageArgs e)
{
string rfc822eml = "";
Guid g = Guid.NewGuid();
lock (g.ToString())
{
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(#"C:\tmpspool");
di.CreateSubdirectory(g.ToString());
string spoolDir = #"C:\tmpspool\" + g.ToString();
SmtpClient Client = new SmtpClient("localhost");
Client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
Client.PickupDirectoryLocation = spoolDir;
Client.Send(e.mailObj);
var files = from file in Directory.EnumerateFiles(spoolDir)
select file;
string serializedEml = files.First();
rfc822eml = File.ReadAllText(serializedEml);
File.Delete(serializedEml);
Directory.Delete(spoolDir);
}
return rfc822eml;
}
It's pretty nasty but it does work. Ideally though, I'd create a new SMTPClient and add in a Serialize function which would return the rfc822 string automatically without it ever hitting the file system.
As I don't seem to be able to trace into the SMTPClient.Send function with Visual Studio, this "ideal" way of doing things is a tad tricky.
I've already sorted out the deserialization of the RFC message by adding in some small changes to Peter Huber's POP3MimeClient and POP3MailClient classes so I can deserialize a file on the HDD or a string back into a MailMessage.
The thing that's nagging at me is that I really should be able to serialize the MailMessaage using a stream and writing the stream to a string -or- file of my choice instead of going around the houses to create GUID based folders as the code above does and reading the content of the file back into a string...
Any pointers as to how I could make this more elegant will be much appreciated.
Thanks.
This will be a hack. Don't forget, MS can change it in the next versions of .Net.
(With the help of ILSpy) you can write an extension method like below
public static class MailExtensions
{
public static string ToEml(this MailMessage mail)
{
var stream = new MemoryStream();
var mailWriterType = mail.GetType().Assembly.GetType("System.Net.Mail.MailWriter");
var mailWriter = Activator.CreateInstance(
type: mailWriterType,
bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic,
binder: null,
args: new object[] { stream },
culture: null,
activationAttributes: null);
mail.GetType().InvokeMember(
name: "Send",
invokeAttr: BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
binder: null,
target: mail,
args: new object[] { mailWriter, true, true });
return Encoding.UTF8.GetString(stream.ToArray());
}
}
and use as
string eml = mailMessage.ToEml();
I finally managed to deserialize the MailMessage after a lot of work:
To get it right, I created a dll which will be used in both the client application and the webservice. This needs to be the same for the deserialization to work :)
I picked the dll serialization classes here: https://bitbucket.org/burningice/compositec1contrib.email/src/0bba07df532c8134717cfb40757f4cb22f002b1d/Email/Serialization/?at=default
Many thanks for sharing!
Once compiled and added my new dll to the projects, the send and receive worked.
So I convert the MailMessage this way : string serializedMessage = SerializeAsBase64(mail);
and in the Webservice, I reconstruct it this way :
MailMessage Mm = DeserializeFromBase64(serializedMessage);
I hope this helps...
I need your help in finding better way in downloading a url using HttpWebResponse
I used next code
HttpWebResponse myboot = HttpWebRequest.Create("http://www.wwenews.us/m1.php?id=441229").GetResponse() as HttpWebResponse;
StreamReader myboot_content = new StreamReader(myboot.GetResponseStream(), Encoding.GetEncoding("windows-1256"));
string temp_data = myboot_content.ReadToEnd();
but a problem says
The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF
appears to me when trying parsing http://www.wwenews.us/m1.php?id=441229
please help me to download string of this site
note: test your solution code before present it as I had tested several solutions and no one solve the problem
Add a reference to System.Configuration to your project and add the following method.
public static bool SetUnsafeHeaderParsing()
{
Assembly oAssembly = Assembly.GetAssembly(typeof(System.Net.Configuration.SettingsSection));
if (oAssembly != null)
{
Type oAssemblyType = oAssembly.GetType("System.Net.Configuration.SettingsSectionInternal");
if (oAssemblyType != null)
{
object oInstance = oAssemblyType.InvokeMember("Section",
BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { });
if (oInstance != null)
{
FieldInfo objFeild = oAssemblyType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
if (objFeild != null)
{
objFeild.SetValue(oInstance, true);
return true;
}
}
}
}
return false;
}
Call the method SetUnsafeHeaderParsing() before you use the HttpWebRequest.Create method call.
Its actually a problem with the server. The server is not following the HTTP specifications. However your .NET client by default would adhere to the specs and flags it as a potential problem.
Skype installed on the same machine as the web server can cause such problems, as it's using the same port (80) by default.
To change that port look here:
http://forum.skype.com/index.php?showtopic=31024
I have a program that does batch processing on some drawings. One of the drawings throws an exception "Error Decrypting Data" when I try to open it. This drawing in particular was generated by a third-party tool other than AutoCAD. In addition, this problem only occurs in AutoCAD 2011. In AutoCAD 2010 it prompts the user that the file was generated outside of AutoCAD but they can click and the batch will continue. I've tried opening it using both the managed .NET API and the COM Interop API but both give the same error.
Here is a post from the AutoCAD formus though it didn't provide me with a solution:
http://forums.autodesk.com/t5/NET/Error-Decrypting-Data-Acad-2011/td-p/2661762/highlight/true
Managed API
string drawingFilePath = #"C:\Drawings\MyDrawing.dwg";
Application.DocumentManager.Open(drawingFilePath, false);
COM Interop
string drawingFilePath = #"C:\Drawings\MyDrawing.dwg";
Object comAutoCAD = Application.AcadApplication;
Object comDocuments = comAutoCAD.GetType().InvokeMember("Documents", BindingFlags.GetProperty, null, comAutoCAD, new object[] { });
Object comDocument = comDocuments.GetType().InvokeMember("Open", BindingFlags.InvokeMethod, null, comDocuments,
new object[] { drawingFilePath, false, Type.Missing });
Document.FromAcadDocument(comDocument);
Someone from the AutoCAD forums posted an answer that works for me.
http://forums.autodesk.com/t5/NET/Error-Decrypting-Data-Acad-2011/td-p/2661762/page/2
Here is an example:
const string systemVar_DwgCheck = "DWGCHECK";
Int16 dwgCheckPrevious = (Int16)Application.GetSystemVariable(systemVar_DwgCheck);
Application.SetSystemVariable(systemVar_DwgCheck, 2);
Document document = Application.DocumentManager.Open(#"C:\Drawings\MyDrawing.dwg", false);
// Do stuff...
Application.SetSystemVariable(systemVar_DwgCheck, dwgCheckPrevious);