MailItem.Display(true|false) exception when used in WinForms - c#

I'm creating an Outlook Add In, which has a subform. The form has a button on it, through which I would like to generate a mailitem, if the user clicks it. I'd like to auto-populate some info in the email, and then leave it for the user to send at their leisure.
My code looks like the following:
private void btnMailDocNotice_Click(object sender, EventArgs e)
{
string clientInfo = string.Empty;
string matInfo = string.Empty;
string author = string.Empty;
string dType = string.Empty;
string fLocation = string.Empty;
string keyWords = string.Empty;
string docName = string.Empty;
clientInfo = this.mCboClient.Text + " " + lblClient;
matInfo = this.mCboMatter.Text + " " + lblMatter;
author = this.txtAuthor.Text;
dType = this.mCboDocType.Text.ToUpper();
fLocation = this.txtSavePath.Text;
keyWords = this.txtKeyWords.Text;
docName = this.txtDocName.Text;
this.sendDocNotice = true;
this.Hide();
CreateMailItem(clientInfo, matInfo, author, dType, this.operatorCode.ToUpper(), fLocation, keyWords, docName);
this.Show();
}
private void CreateMailItem(string clientInfo, string matInfo, string author, string dType, string profiledBy, string fLocation, string keyWords, string docName)
{
this.DNoticeItem = (Outlook.MailItem)ThisAddIn.myApp.CreateItem(Outlook.OlItemType.olMailItem);
this.DNoticeItem.Subject = "Document: " + docName;
this.DNoticeItem.HTMLBody = "<span style=\"font-family:Calibri; font-size: 11pt;\">KeyWords: " + keyWords + "</span>";
this.DNoticeItem.HTMLBody += "<br />Client: " + clientInfo;
this.DNoticeItem.HTMLBody += "<br />Matter: " + matInfo;
this.DNoticeItem.HTMLBody += "<br />Author: " + author;
this.DNoticeItem.HTMLBody += "<br />Doc Type: " + dtClient;
this.DNoticeItem.HTMLBody += "<br />Profiled by: " + profiledBy;
this.DNoticeItem.HTMLBody += "<br />File://" + fLocation;
this.DNoticeItem.Importance = Outlook.OlImportance.olImportanceNormal;
this.DNoticeItem.Display(false);
}
The problem that I'm running into, is it fires an exception on the mailitem.display function, whether I use true or false (doing a bit of research says that determines if the user can access the main Outlook window or not while the mailitem is open). The exception is a COM Exception of "A dialog box is open. Close it and try again". I've tried hiding the WinForm prior to the function call that creates the mail item, then show it again after the function is exited, but it didn't work. I've tried a version of the code where I use System.Diagnostics.Process.Start() to try and open the file after saving it to disk, and while it doesn't fire an exception from the add in, Outlook prompts the user with a message box of the same message from the ComException. I even tried creating a field to see if the doc notice email should be drafted, and thought to have the code take care of that after a form.close() call, thinking the close call would at least dispose of the dialog box that was locking Outlook, and I still got the same exception.
Is there a way to achieve what I want? Does anyone have any suggestions? I'm kind of stuck at the moment, and would appreciate any help/pointers/suggestions anyone has to offer in this issue. My sincere apologies if this is a duplicative question - I couldn't find a good answer to the question. Thank you in advance for your time.

Firstly, why not display yoru own form modelessly?
Secondly (and this is pretty important) do not use code like the following
this.DNoticeItem.HTMLBody += "<br />Client: " + clientInfo;
Every time you run a line like that, you retrieve HTMLBody, add some stuff to it (making the HTML malformed), then set HTMLBody again and force Outlook to make sense of your (malformed) HTML. This (assuming Outlook can parse and fix your HTML) will result in HTML being returned to be different from what you set it to.
Build the HTML body once using a regular string, and set HTMLBody property only once.

Related

How to get mail informations from its local path and ReplyAll to it using Outlook application

So i need to get informations such as :
Sender mail address (to later get his Domain profile informations)
Mail subject (which should be the "filepath" minus the "msg" extension anyway).
And then, replying to it just like i would push "ReplyAll" button in Outlook. So the reply needs to get the usual Headers such as "From : ....", "To : ...", "Cc : ..." and so on.
All i need is to change its subject, and delete the address depending on the "FromAddress" of the user that will push the button
I've read a bit here and there, and people are talking about a MailItem, but there's no informations about HOW to get this item or how to build it from a .msg file.
What i have to do comes after a specific user action.
The user is supposed to Drag&Drop the mail into a panel, from there i get its local path.
Thanks for your time !
Edit#1
I managed to find out to get informations and to set a .msg file to a MailItem :
Outlook.Application appOutlook = new Outlook.Application();
var email = (Outlook.MailItem)appOutlook.Session.OpenSharedItem(filepath);
string getCC = "";
string getFrom = ""; // From is never null
string getTo = "";
string getSubject = "";
bool lengthCC = email.CC.HasValue();
bool lengthTo = email.To.HasValue();
bool lengthSubject = email.Subject.HasValue();
if (lengthCC)
{
getCC = email.CC.ToString();
}
// and so on...
//
// Display it in MessageBox to confirm test succeeded :
MessageBox.Show("CC : " + getCC +
"\nFrom : " + getFrom +
"\nTo : " + getTo +
"\nSubject : " + getSubject);
email.Close(Outlook.OlInspectorClose.olDiscard);
Now i just need to build the ReplyAll Body and add headers manually myself i guess...
Edit#2
No need to rewrite Headers apparently, doing so :
Outlook._MailItem reply = email.ReplyAll();
reply.To = getFrom;
reply.CC = getCC;
reply.Body = "SomeReplyMessage" + reply.Body;
reply.Send();
Marshal.ReleaseComObject(appOutlook);
Marshal.ReleaseComObject(email);
Marshal.ReleaseComObject(reply);
But it erased the separator above the original message, i'll find a way to re-add it !!!
Edit#3
And there it is, the so-called "separator" wasn't displaying, because i wasn't re-stating an HTML Body !
So, to keep it you can do this :
reply.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
string ReplyMessageBody = String.Format("AddSome<br>HTMLCode<br>ThereAndHere<br>ButFinishWith : BodyTag</body>");
reply.HTMLBody = ReplyMessageBody + reply.HTMLBody;
Or simpler if you don't need your reply to be an HTML one :
reply.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
reply.HTMLBody = "AddSomeReplyMessage" + reply.HTMLBody;
Outlook does not work directly wit MSG files - when you call CreateFromTemplate or even OpenSharedItem, Outlook creates a new item in its default store and imports the MSG or OFT file. It does not expose anything that would you let you figure out that the message came from a file; the item is indistinguishable from an item created directly using CreateItem or MAPIFolder.Items.Add.
See edits on original question for answer !

Adding forward text to email

I'm having a slight problem with adding text to forwarding emails. This is my current code:
private void ForwardFunction(Outlook.MailItem email)
{
Outlook.MailItem forwardEmail = ((Outlook._MailItem)email).Forward();
Outlook.Inspector forwardInsp = forwardEmail.GetInspector;
Word.Document forwardDoc = forwardInsp.WordEditor;
Word.Range forwardRange = forwardDoc.Range(0,1);
string forwardText = "This is some text";
forwardRange.Text = forwardText + forwardRange.text
newEmail.Recipients.Add("myemail");
forwardEmail.Save();
((Outlook._MailItem)forwardEmail).Send();
}
I've gone through it and it does add the text to the range, but when I receive the forwarded email it doesn't contain any of the additional text. I've used similar code to edit current emails that the user is editing (New, Replies/Forwards, InlineResponses) with success, but the email being passed to the function is the currently selected email in the inbox. Not sure if this matters, maybe because it's not being edited by the user.
I couldn't find a specific way to add new text to a programmatically forwarded email.
For anyone else interested in this, I ended up using the .HTMLBody. It seems that using the .GetInspector either gets the inspector of the _email instead of fEmail and you can't edit it or it gets the correct inspector but it can't edit it. Either way, using the .HTMLBody seems to get around it.
Outlook.MailItem fEmail = ((Outlook._MailItem)_email).Forward();
string forwardText;
forwardText = "class=MsoNormal>";
forwardText += "This is my forwarded message";
forwardText += "Bonus hyper link <a href='" + hyperlinkText + "'>" + hyperlinkText + "</a>";
var regex = new Regex(Regex.Escape("class=MsoNormal>"));
fEmail.HTMLBody = regex.Replace(fEmail.HTMLBody, forwardText, 1);
fEmail.Save();
fEmail.AutoForwarded = true;
((Outlook._MailItem)fEmail).Send();

can't get the body/attachments of new mails in outlook

I've developed an Outlook plugin using C# where for each new mail received, i get(and save) the sender/subject/the body of email & the attachments. Well, the last 2 gave me a headache. I can see the sender and the subject of the new mail but for the body&attachments it seems that is a problem. I've used NewMailEx for getting the new mails in Inbox. The function looks like this:
private void Application_NewMailEx(string EntryIDCollection)
{
string[] entryIdArray = EntryIDCollection.Split(',');
foreach (string entryId in entryIdArray)
{
try
{
Outlook.MailItem item = (Outlook.MailItem)Application.Session.GetItemFromID(EntryIDCollection, null);
string subj = item.Subject; //works
string to = item.To; //works
string bec = item.BCC; //does not work but dont care
string body = item.Body; //DOES NOT SAVE THE BODY OF THE NEW MAIL RECEIVED
string final = "Sender: " + item.SenderEmailAddress + "\r\n" + "Subject: " + subj + "\r\n" + "BCC: " + bec + "\r\n" + "TO: " + to + "\r\n\n" + "Body: " + body + "\r\n\n";
System.IO.File.AppendAllText(#"D:\tmp\atr.txt", final);
//the result of item.attachments.count is always 0 , even though I've
//sent mails with a different number of attachments. So the if
//statement is false
if (item.Attachments.Count > 0)
{
for (int i = 1; i <= item.Attachments.Count; i++)
{
item.Attachments[i].SaveAsFile(#"D:\tmp\" + item.Attachments[i].FileName);
}
}
Marshal.ReleaseComObject(item);
}
catch (System.Exception e)
{
MessageBox.Show(e.Message);
}
}
}
Where does the Item variable come from? You need to initialize it using Application.Session.getItemfromID().
I'm writing in VBA, so I feel like posting my code here would be a faux pas, but I have come to a solution using similar Object Libraries from the Outlook application that I think transfer well to your C++ intentions.
First of all, switching to POP3 certainly fixes this problem, but you're stuck using POP3, which is only ideal from a programming standpoint.
The solution I have found follows this algorithm:
//Generate Outlook MailItem Object, "item"
//If item.DownloadState is not 1,
//item.Display
//item.Close(1)
//Perform end of code operations
//Call Function that is identical to Application_NewMailEx but is not Application_NewMailEx because Application_NewMailEx is a function that is thrown during the incoming mail event.
//Else,
//Perform Intended Code
You see how calling a function identical to Application_NewMailEx creates a kind of loop because if item.DownloadState is not 1, you'll be calling that function again? I get that this isn't the most ideal coding practice, but I have scoured the internet and Outlook Application and Outlook Object Library experts have no idea how to solve this problem any other way (in fact, no one even proposes THIS solution)
For my full VBA Solution Check out:
https://superuser.com/questions/894972/outlook-strange-item-attachments-error/990968#990968

Why is this alertbox not appearing?

I've got almost got a web project finished for an assignment, but I've hit a stumbling block in the form of an alertbox that refuses to pop up when called. The assignment is to create a web form for users to submit personal information to a website. Once they fill in all the textboxes and click a button to register, that will call the function registerMe in the code behind as seen below. Once they do that, the idea is that the function will first check to make sure that the user hasn't already registered on the website, then it will stuff all the values from the Textboxes into a Session object (which is using Candidate.curCandidate as a wrapper). This Session object will then be added to the Application state data to save it.
Now, here's the weird thing. In the if statement below, if the statement is true, all the values will be saved to the session and then the Application state data as desired, but the Alertbox won't appear. However, if the if statement is false, an Alertbox WILL appear. So, I'm guessing that somehow reading and writing all these values is interfering with the activation of an Alertbox, but I have no idea why.
protected void registerMe(object sender, EventArgs e)
{
String successText;
if (Candidate.curCandidate.appProperty == false)
{
Candidate.curCandidate.ssNumberProperty = socSec.Text;
Candidate.curCandidate.emailAddressProperty = email.Text;
Candidate.curCandidate.userIDProperty = userName0.Text;
Candidate.curCandidate.passwordProperty = password0.Text;
Candidate.curCandidate.dateOfBirthProperty = dateBirth.Text;
Candidate.curCandidate.firstNameProperty = fName0.Text;
Candidate.curCandidate.lastNameProperty = lName0.Text;
Candidate.curCandidate.streetAddressProperty = strAdd0.Text;
Candidate.curCandidate.cityProperty = city0.Text;
Candidate.curCandidate.stateProperty = state0.Text;
Candidate.curCandidate.positionProperty = jobs0.SelectedIndex;
Candidate.curCandidate.applicationStatusProperty = appStatus0.Text;
Candidate.curCandidate.appProperty = true;
Application[Candidate.curCandidate.ssNumberProperty]=Candidate.curCandidate;
successText = "Thank you. Candidate Information Added Successfully.\n" +
"E-Mail Address You Entered will be used to notify you of any\n" +
"updates for the position you applied for.";
ClientScript.RegisterStartupScript(this.GetType(), "myalert",
"alert('" + successText + "');", true);
}
else
{
successText = "Registration unsuccessful.";
ClientScript.RegisterStartupScript(this.GetType(), "myalert",
"alert('" + successText + "');", true);
}
}
Try to remove \n from successText and see if it works.
If you really need it, try to double escape it like below:
successText = "... Successfully.\\n"

Creating a customized "Yes / No" alert box in asp.net (javascript) - Part 2

I am trying to create a customized messagebox using javascript but not getting too far.
string txtConfirmMessage = "On " + DateTime.Now + ", ";
txtConfirmMessage = txtConfirmMessage + sUserID;
txtConfirmMessage = txtConfirmMessage + " added this record. Do you want to continue? ";
btnSubmit.OnClientClick = #"return confirm('" + txtConfirmMessage + "' Do you want to continue);";
I need to display a custom message involving the UserID, the date, and the value that the user has enetered. When I click the Submit button, the messagebox does not pop up.
Update:
I know this code is executed at the Page_Load event. However, is it possible to display in this alert box, a value that the user has selected (that action occurs after the page load event) ?
Any ideas to resolve this issue?
The javascript that you have is not valid, as the "confirm" method taks a single parameter, but you are giving it two bits.
Try this modified version.
string messageFormat = "On {0}, {1} added this record. Do you want to continue?";
string formattedMessage = string.format(messageFormat, DateTime.Now, sUserID);
btnSubmit.OnClientClick = "return confirm('" + formattedMessage + "');";
You just have an extra string after the one you're passing to confirm(), change it to this:
btnSubmit.OnClientClick = #"return confirm('" + txtConfirmMessage + "');";
About the update of the question, you could assign an OnClientClick event handler to the button as late as PreRender and the value will be persisted in the ViewState.

Categories