问题
I am using the Microsoft.Office.Interop.Outlook.Application
to generate an email and display it on the screen before the user can send it. The application is a winform
application coded in C#
in the .NET Framework 3.5 SP1
and it is Microsoft Outlook 2003
. I am using the following code:
public static void GenerateEmail(string emailTo, string ccTo, string subject, string body)
{
var objOutlook = new Application();
var mailItem = (MailItem)(objOutlook.CreateItem(OlItemType.olMailItem));
mailItem.To = emailTo;
mailItem.CC = ccTo;
mailItem.Subject = subject;
mailItem.HTMLBody = body;
mailItem.Display(mailItem);
}
My question is:
How do i insert/add the default signature of the user who is using the application in the body
of the email generated?
Any help appreciated.
回答1:
Take a look at the link below. It explains where the signatures can be found in the file system as well as how to read them properly.
http://social.msdn.microsoft.com/Forums/en/vsto/thread/86ce09e2-9526-4b53-b5bb-968c2b8ba6d6
The thread only mentions Window XP and Windows Vista signature locations. I have confirmed that Outlooks signatures on Windows 7 live in the same place as Vista. I have also confirmed that the signature location is the same for Outlook 2003, 2007, and 2010.
Here's a code sample if you choose to go this route. Taken from this site.
private string ReadSignature()
{
string appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Microsoft\\Signatures";
string signature = string.Empty;
DirectoryInfo diInfo = new DirectoryInfo(appDataDir);
if(diInfo.Exists)
{
FileInfo[] fiSignature = diInfo.GetFiles("*.htm");
if (fiSignature.Length > 0)
{
StreamReader sr = new StreamReader(fiSignature[0].FullName, Encoding.Default);
signature = sr.ReadToEnd();
if (!string.IsNullOrEmpty(signature))
{
string fileName = fiSignature[0].Name.Replace(fiSignature[0].Extension, string.Empty);
signature = signature.Replace(fileName + "_files/", appDataDir + "/" + fileName + "_files/");
}
}
}
return signature;
}
Edit: See here to find the name of the default signature for Outlook 2013 or @japel's answer in this thread for 2010.
回答2:
There is a really quick easy way that hasn't been mentioned. See modified below:
public static void GenerateEmail(string emailTo, string ccTo, string subject, string body)
{
var objOutlook = new Application();
var mailItem = (MailItem)(objOutlook.CreateItem(OlItemType.olMailItem));
mailItem.To = emailTo;
mailItem.CC = ccTo;
mailItem.Subject = subject;
mailItem.Display(mailItem);
mailItem.HTMLBody = body + mailItem.HTMLBody;
}
By editing the HTMLBody after you display the mailitem you allow for Outlook to do the work of adding the default signature and then essentially copy, edit, and append.
回答3:
I have had the exact same problem, but was able to solve it with Interop only, and thus get the default signature.
The trick is to call GetInspector, which will magically set the HTMLBody property to the signature. Just reading the GetInspector property is enough. I tested this with Windows 7 / Outlook 2007.
Credits to this blog post for the solution.
回答4:
For some reason libraries are made a bit different depending on language installed. Also a signature can hold a logo-image, wich I do not know why, but it is made in 2 files in 2 different sizes.
private string ReadSignature()
{
string appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Microsoft\\Signatures";
string signature = string.Empty;
DirectoryInfo diInfo = new DirectoryInfo(appDataDir);
if (diInfo.Exists)
{
FileInfo[] fiSignature = diInfo.GetFiles("*.htm");
if (fiSignature.Length > 0)
{
StreamReader sr = new StreamReader(fiSignature[0].FullName, Encoding.Default);
signature = sr.ReadToEnd();
if (!string.IsNullOrEmpty(signature))
{
string fileName = fiSignature[0].Name.Replace(fiSignature[0].Extension, string.Empty);
signature = signature.Replace(fileName + "_files/", appDataDir + "/" + fileName + "_files/");
}
}
}
else
{
appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Microsoft\\Signaturer";
signature = string.Empty;
diInfo = new DirectoryInfo(appDataDir);
if (diInfo.Exists)
{
FileInfo[] fiSignature = diInfo.GetFiles("*.htm");
if (fiSignature.Length > 0)
{
StreamReader sr = new StreamReader(fiSignature[0].FullName, Encoding.Default);
signature = sr.ReadToEnd();
if (!string.IsNullOrEmpty(signature))
{
string fileName = fiSignature[0].Name.Replace(fiSignature[0].Extension, string.Empty);
signature = signature.Replace(fileName + "_files/", appDataDir + "/" + fileName + "_files/");
}
}
}
}
if (signature.Contains("img"))
{
int position = signature.LastIndexOf("img");
int position1 = signature.IndexOf("src", position);
position1 = position1 + 5;
position = signature.IndexOf("\"", position1);
billede1 = appDataDir.ToString() + "\\" + signature.Substring(position1, position - position1);
position = billede1.IndexOf("/");
billede1 = billede1.Remove(position, 1);
billede1 = billede1.Insert(position, "\\");
billede1 = System.Web.HttpUtility.UrlDecode(billede1);
position = signature.LastIndexOf("imagedata");
position1 = signature.IndexOf("src", position);
position1 = position1 + 5;
position = signature.IndexOf("\"", position1);
billede2 = appDataDir.ToString() + "\\" + signature.Substring(position1, position - position1);
position = billede2.IndexOf("/");
billede2 = billede2.Remove(position, 1);
billede2 = billede2.Insert(position, "\\");
billede2 = System.Web.HttpUtility.UrlDecode(billede2);
}
return signature;
}
Getting and inserting the signature: Global variables:
string billede1 = string.Empty; // holding image1
string billede2 = string.Empty; // holding image2
string signature = ReadSignature();
if (signature.Contains("img"))
{
int position = signature.LastIndexOf("img");
int position1 = signature.IndexOf("src", position);
position1 = position1 + 5;
position = signature.IndexOf("\"", position1);
//CONTENT-ID
const string SchemaPR_ATTACH_CONTENT_ID = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E";
string contentID = Guid.NewGuid().ToString();
//Attach image
mailItem.Attachments.Add(@billede1, Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue, mailItem.Body.Length, Type.Missing);
mailItem.Attachments[mailItem.Attachments.Count].PropertyAccessor.SetProperty(SchemaPR_ATTACH_CONTENT_ID, contentID);
//Create and add banner
string banner = string.Format(@"cid:{0}", contentID);
signature = signature.Remove(position1, position - position1);
signature = signature.Insert(position1, banner);
position = signature.LastIndexOf("imagedata");
position1 = signature.IndexOf("src", position);
position1 = position1 + 5;
position = signature.IndexOf("\"", position1);
//CONTENT-ID
// const string SchemaPR_ATTACH_CONTENT_ID = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E";
contentID = Guid.NewGuid().ToString();
//Attach image
mailItem.Attachments.Add(@billede2, Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue, mailItem.Body.Length, Type.Missing);
mailItem.Attachments[mailItem.Attachments.Count].PropertyAccessor.SetProperty(SchemaPR_ATTACH_CONTENT_ID, contentID);
//Create and add banner
banner = string.Format(@"cid:{0}", contentID);
signature = signature.Remove(position1, position - position1);
signature = signature.Insert(position1, banner);
}
mailItem.HTMLBody = mailItem.Body + signature;
The stringhandling can be don smarter, but this Works and gave me my sinature God luck.
回答5:
I have got around the problem by mainly being 'sneaky'. If, when you make a new email in Outlook by Ctrl+N, it inserts the default signature, I store that blank email (with signature) in a temporary string then append that string to another string that has the content in it.
Here is some code to demonstrate it:
string s = "";
Outlook.Application olApp = new Outlook.Application();
Outlook.MailItem mail = olApp.CreateItem(Outlook.OlItemType.olMailItem);
mail.To = "Hi@World.com";
mail.Subject = "Example email";
s = mainContentAsHTMLString + mail.HTMLBody;
mail.Display();
mail.HTMLBody = s;
回答6:
I've found a very easy way to attach the default outlook signature (including images). The trick is to retrieve the body message after calling the GetInspector and concat your message to that.
Imports Microsoft.Office.Interop
Dim fdMail As Outlook.MAPIFolder
Dim oMsg As Outlook._MailItem
oMsg = fdMail.Items.Add(Outlook.OlItemType.olMailItem)
Dim olAccounts As Outlook.Accounts
oMsg.SendUsingAccount = olAccounts.Item(1)
oMsg.Subject = "XXX"
oMsg.To = "xxx@xxx.com"
Dim myInspector As Outlook.Inspector = oMsg.GetInspector
Dim text As String
text = "mail text" & oMsg.HTMLBody
oMsg.HTMLBody = text
oMsg.Send()
回答7:
For anyone looking for an answer after all those years.
In Outlook 2016 mailItem.HTMLBody already contains your default signature/footer.
In my case I replied to someone. If you want to add a message before just do as shown below. Simple.
MailItem itemObj = item as MailItem; //itemObj is the email I am replying to
var itemReply = itemObj.Reply();
itemReply.HTMLBody = "Your message" + itemReply.HTMLBody; //here happens the magic, your footer is already there in HTMLBody by default, just don't you delete it :)
itemReply.Send();
回答8:
also I have dealt with this topic for several hours. Finally I stumbled across a very interesting Microsoft support case.
https://support.microsoft.com/de-de/help/4020759/text-formatting-may-be-lost-when-editing-the-htmlbody-property-of-an
The real problem is buried somewhere else: Microsoft Outlook uses Microsoft Word as the editor. Loss of formatting may occur if the HTML source is verified by the Word HTML module when the item is sent.
To fix the problem, simply load Word.Interopt and use Word as the editor.
Translated with www.DeepL.com/Translator
public static void SendMail(string subject, string message, List<string> attachments, string recipients)
{
try
{
Outlook.Application application = new Outlook.Application();
Outlook.MailItem mailItem = (Outlook.MailItem)application.CreateItem(Outlook.OlItemType.olMailItem);
Word.Document worDocument = mailItem.GetInspector.WordEditor as Word.Document;
Word.Range wordRange = worDocument.Range(0, 0);
wordRange.Text = message;
foreach (string attachment in attachments ?? Enumerable.Empty<string>())
{
string displayName = GetFileName(attachment);
int position = (int)mailItem.Body.Length + 1;
int attachType = (int)Outlook.OlAttachmentType.olByValue;
Outlook.Attachment attachmentItem = mailItem.Attachments.Add
(attachment, attachType, position, displayName);
}
mailItem.Subject = subject;
Outlook.Recipients recipientsItems = (Outlook.Recipients)mailItem.Recipients;
Outlook.Recipient recipientsItem = (Outlook.Recipient)recipientsItems.Add(recipients);
recipientsItem.Resolve();
mailItem.Display();
recipientsItem = null;
recipientsItems = null;
mailItem = null;
application = null;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
private static string GetFileName(string fullpath)
{
string fileName = Path.GetFileNameWithoutExtension(fullpath);
return fileName;
}
Have fun with it. Thomas
回答9:
To get/set the user's default signature you can use the windows registry. Example for Outlook 2010: HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\MailSettings Name: NewSignature Datatype: String Value: (name of signature file without ending)
回答10:
I have a variant solution to this issue which is worth sharing and is complete for the purpose of sending an email from ANY Outlook Account with the email text merged with ANY signature which you can select.
Assumptions:
You have added a reference to the HtmlAgilityPack which is used to format the HTML content.
As I could find no way (except via the registry) to get the email account signature, this is passed as a text value and can be set as a parameter in the program or by looking in the registry settings for the Outlook Account.
The from account is a valid email account on the system The signature file was created by Outlook using the html format.
I am sure there are numerous possible improvements to this.
/// <summary>
/// Sends an email from the specified account merging the signature with the text array
/// </summary>
/// <param name="to">email to address</param>
/// <param name="subject">subect line</param>
/// <param name="body">email details</param>
/// <returns>false if account does not exist or there is another exception</returns>
public static Boolean SendEmailFromAccount(string from, string to, string subject, List<string> text, string SignatureName)
{
// Retrieve the account that has the specific SMTP address.
Outlook.Application application = new Outlook.Application();
Outlook.Account account = GetAccountForEmailAddress(application, from);
// check account
if (account == null)
{
return false;
}
// Create a new MailItem and set the To, Subject, and Body properties.
Outlook.MailItem newMail = (Outlook.MailItem)application.CreateItem(Outlook.OlItemType.olMailItem);
// Use this account to send the e-mail.
newMail.SendUsingAccount = account;
newMail.To = to;
newMail.Subject = subject;
string Signature = ReadSignature(SignatureName);
newMail.HTMLBody = CreateHTMLBody(Signature, text);
((Outlook._MailItem)newMail).Send();
return true;
}
private 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));
}
/// <summary>
/// Return an email signature based on the template name i.e. signature.htm
/// </summary>
/// <param name="SignatureName">Name of the file to return without the path</param>
/// <returns>an HTML formatted email signature or a blank string</returns>
public static string ReadSignature(string SignatureName)
{
string appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Microsoft\\Signatures";
string signature = string.Empty;
DirectoryInfo diInfo = new DirectoryInfo(appDataDir);
if
(diInfo.Exists)
{
FileInfo[] fiSignature = diInfo.GetFiles("*.htm");
foreach (FileInfo fi in fiSignature)
{
if (fi.Name.ToUpper() == SignatureName.ToUpper())
{
StreamReader sr = new StreamReader(fi.FullName, Encoding.Default);
signature = sr.ReadToEnd();
if (!string.IsNullOrEmpty(signature))
{
// this merges the information in the signature files together as one string
// with the correct relative paths
string fileName = fi.Name.Replace(fi.Extension, string.Empty);
signature = signature.Replace(fileName + "_files/", appDataDir + "/" + fileName + "_files/");
}
return signature;
}
}
}
return signature;
}
/// <summary>
/// Merges an email signature with an array of plain text
/// </summary>
/// <param name="signature">string with the HTML email signature</param>
/// <param name="text">array of text items as the content of the email</param>
/// <returns>an HTML email body</returns>
public static string CreateHTMLBody(string signature, List<string> text)
{
try
{
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
HtmlAgilityPack.HtmlNode node;
HtmlAgilityPack.HtmlNode txtnode;
// if the signature is empty then create a new string with the text
if (signature.Length == 0)
{
node = HtmlAgilityPack.HtmlNode.CreateNode("<html><head></head><body></body></html>");
doc.DocumentNode.AppendChild(node);
// select the <body>
node = doc.DocumentNode.SelectSingleNode("/html/body");
// loop through the text lines and insert them
for (int i = 0; i < text.Count; i++)
{
node.AppendChild(HtmlAgilityPack.HtmlNode.CreateNode("<p>" + text[i] + "</p>"));
}
// return the full document
signature = doc.DocumentNode.OuterHtml;
return signature;
}
// load the signature string as HTML doc
doc.LoadHtml(signature);
// get the root node and insert the text paragraphs before the signature in the document
node = doc.DocumentNode;
node = node.FirstChild;
foreach (HtmlAgilityPack.HtmlNode cn in node.ChildNodes)
{
if (cn.Name == "body")
{
foreach (HtmlAgilityPack.HtmlNode cn2 in cn.ChildNodes)
{
if (cn2.Name == "div")
{
// loop through the text lines backwards as we are inserting them at the top
for (int i = text.Count -1; i >= 0; i--)
{
if (text[i].Length == 0)
{
txtnode = HtmlAgilityPack.HtmlNode.CreateNode("<p class=\"MsoNormal\"><o:p> </o:p></p>");
}
else
{
txtnode = HtmlAgilityPack.HtmlNode.CreateNode("<p class=\"MsoNormal\">" + text[i] + "<o:p></o:p></p>");
}
cn2.InsertBefore(txtnode, cn2.FirstChild);
}
// return the full document
signature = doc.DocumentNode.OuterHtml;
}
}
}
}
return signature;
}
catch (Exception)
{
return "";
}
}
回答11:
Using GetInspector causes an exception when implementing an Interceptor using the Inspectors_NewInspector event. You will also find that the Signature has yet to be added to the MailItem when the Inspectors_NewInspector event is raised.
If you trigger the Item.Send() with your own code (e.g. your own button) you will have an Anchor tag <a>
for both the "Signature" and "Content End". Note these tags are removed from the HTMLBody (in the translation from Word HTML to HTML) if you handle the Outlook ribbon [Send] button click event yourself (as is common for Add-ins).
My solution this is to handle the Item.Open event so that when the Interceptor/Inspectors_NewInspector is created/raised I can then add an Id attribute to the containing <p>
tag to later use when sending. This attribute stays in the HTML even after sending.
This ensures that whenever the Send is called I can detect in my code the "Signature" or the "Content End" paragraphs.
来源:https://stackoverflow.com/questions/6442747/add-the-default-outlook-signature-in-the-email-generated