Search code examples
c#vstooutlook-addinoutlook-2019

VSTO send email from custom Form button in Outlook


My goal, the user wants to send a new email, after filling in (.TO, .CC, .Body etc) and clicking on the send button will display a custome Form where the sending options are. One option is to send the email as the user created it (normal send button function). Is there any idea how to assign ItemSend function to button in custom form ?

ThisAddIn.cs -> open custom Form

public partial class ThisAddIn
{
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);

    }

Application_ItemSend

   private void Application_ItemSend(object Item, ref bool Cancel)
   {
        if (Item is Outlook.MailItem)
        {
            Form1 f = new Form1();
            f.Show();
        }

        Cancel = true;
    }

ChooseFormSend.cs -> custom sending button,

    public void btn_standard_Click(object sender, System.EventArgs e)
    {
         //mail.Send() -> send email which user whant to send        

    }

UPDATE (all aswers to gether, to make this work)

ThisAddIn.cs

public partial class ThisAddIn
{
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);

    private bool ProcessEmail(Outlook.MailItem mailItem, MailSendType SendType)
    {
        switch (SendType)
        {
            case MailSendType.Normal:
                return false;

            case MailSendType.WithAdverts:
                //mailItem.BCC += "[email protected]";
                mailItem.HTMLBody += @"<b>Some bold text at the end :)</b>";
                mailItem.HTMLBody += @"1233";
                return false; // send the mail

            case MailSendType.WithCoupon:
                mailItem.CC += "[email protected]";
                mailItem.HTMLBody += @"";
                return false; // send the mail

            // by default don't send the mail
            default:
                return true;
        }
    }

    private void Application_ItemSend(object Item, ref bool Cancel)
    {
        if (Item is MailItem) // ensures Item is a mail item
        {
            using (Form1 form_ChooseForm = new Form1())
            {
                DialogResult dr = form_ChooseForm.ShowDialog();
                if (dr == DialogResult.OK) // shows the form as a dialog
                {
                    Cancel = ProcessEmail((MailItem)Item, form_ChooseForm.SendType);
                    // MessageBox.Show("The OK button on the form was clicked.");                 
                }
                else
                {
                    // MessageBox.Show("Cancel process");
                    Cancel = true;
                }
            }   
        }
    }
}

ChooseFormSend.cs

using Microsoft.Office.Core;
using Microsoft.Office.Interop.Outlook;
using Microsoft.Office.Tools.Outlook;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Mail;
using System.Runtime.InteropServices;

namespace OutlookControll

{
    public enum MailSendType
    {
        NoSend,
        Normal,
        WithAdverts,
        WithCoupon
    }
    public partial class Form1 : Form
    {
    public Form1()
    {
        InitializeComponent();
    }

    public MailSendType SendType = MailSendType.NoSend;

    private void Btn_ShowSecondForm_Click(object sender, EventArgs e)
    {
        AddItemsForm f2 = new AddItemsForm();
        f2.ShowDialog();
        this.Hide();
    }

    private void Btn_cancel_Click(object sender, EventArgs e)
    {
        Button Btn_cancel_Click = new Button();
        Btn_cancel_Click.DialogResult = DialogResult.Cancel;
        this.Hide();
    }

    public void Btn_standard_Click(object sender, EventArgs e)
    {
        Button Btn_standard_Click = new Button();
        Btn_standard_Click.DialogResult = DialogResult.OK;
        Controls.Add(Btn_standard_Click);
        SendType = MailSendType.Normal;
        this.Hide();
    }

}

Btn_standard_Click.DialogResult = DialogResult.OK can be setup in Properties -> Behavior -> DialogResult -> OK, Cancel, Abort, etc.


Solution

  • There are 3 potential scenarios I can consider:

    1. Press send > Form pops up > Select option on Form > Modify email contents > Send email
    2. Press send > Form pops up > Select option on Form > Create and send new email (sending 1 or more new emails)(discard old email) > Send email
    3. Press send > Form pops up > Select option on Form > Create and send new email (sending 1 or more new emails)(send old email) > Send email

    Note that once modifying the email contents can mean modifying everything. Change the sender change the subject etc. So if you want to create a single new email and discard the old one option 1 still works to just manipulate the original email completely.

    The Dialog to allow the user to select the relevant options.

    Note: When placing the form buttons ensure to set the DialogResult option under Behavior in the properties inspector. This allows for a DialogResult:OK to be returned once clicking one of the buttons automatically closing and returning from the dialog.

    public enum MailSendType
    {
        NoSend,
        Normal,
        WithAdverts,
        WithCoupon
    }
    
    public partial class SendItemForm : Form
    {
        public SendItemForm()
        {
            InitializeComponent();
        }
    
        public MailSendType SendType = MailSendType.NoSend;
    
        private void button1_Click(object sender, EventArgs e)
        {
            SendType = MailSendType.Normal;
        }
    
        private void button2_Click(object sender, EventArgs e)
        {
            SendType = MailSendType.WithAdverts;
        }
    }
    

    Option 1: Only modifying the contents of the email

    Note the show f.ShowDialog() instead of f.Show() this stops the current thread from continuing the send operation and waits for the user to select a button on the form. The f.SendType from the dialog is set and used to indicated which option the user selected. Using ProcessEmail the email can me manipulated and return false results in the manipulated email being send as the false propagates down to parent functions Cancel = false (Don't cancel the send).

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            // create a global event listener for sending items
            Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
        }
    
        // this function is used to modify the mail object before sending it (More variables could be added to extend the functionality)
        private bool ProcessEmail(Outlook.MailItem mailItem, MailSendType sendType)
        {
            switch (sendType)
            {
                case MailSendType.Normal:
                    return false; // send the mail as is don't mainpulate the mailItem variable
    
                case MailSendType.WithAdverts:
                    mailItem.BCC += "[email protected]";
                    mailItem.HTMLBody += @"<b>Some bold text at the end :)</b>";
                    mailItem.HTMLBody += @"</img src='https://server.xyz/ad1.png'>";
                    return false; // send the mail
    
                case MailSendType.WithCoupon:
                    mailItem.CC += "[email protected]";
                    mailItem.HTMLBody += @"</img src='https://server.xyz/coupon1.png'>";
                    return false; // send the mail
    
                // by default don't send the mail
                default:
                    return true;
            }
        }
    
        private void Application_ItemSend(object Item, ref bool Cancel)
        {
            if (Item is Outlook.MailItem) // ensures Item is a mail item
            {
                using (SendItemForm f = new SendItemForm()) // creates the form
                    if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK) // shows the form as a dialog
                        //if statement ensures the process will only proceed if an OK is returned 
                        //(The form has a cancel button or it could crash or anything else)
                        Cancel = ProcessEmail((Outlook.MailItem)Item, f.SendType); // process the email with the SendType
            }
        }
    

    Option 2/3 Sending new emails

    This method highlights how to send new emails in outlook. Note: Tested sending email with MailItem.Send() and it does not call Application_ItemSend again

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
        }
    
        private void SendNewEmail(string to, string greeting, MailSendType sendType)
        {
            Outlook.MailItem newMailItem = Application.CreateItem(Outlook.OlItemType.olMailItem);
            newMailItem.To = to;
            newMailItem.SendUsingAccount = Application.Session.Accounts[1]; // Optional can leave blank to send from default account (Array starts at 1)
            newMailItem.Subject = "New Mail";
            newMailItem.Body = $"{greeting} {newMailItem.To}\nExample Body from {sendType.ToString()}";
    
            // Part of Original answer but it's not relevant. However I will leave it in the event that it is of use to someone
            //((Outlook.ItemEvents_10_Event)newMailItem).Send += (ref bool Cancel) => { /*do nothing*/ };
    
            newMailItem.Send(); // send the mail
        }
    
        private void Application_ItemSend(object Item, ref bool Cancel)
        {
            if (Item is Outlook.MailItem) // ensures Item is a mail item
            {
                using (SendItemForm f = new SendItemForm()) // creates the form
                    if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK) // shows the form as a dialog
                    {
                        //if statement ensures the process will only proceed if an OK is returned 
                        //(The form has a cancel button or it could crash or anything else)
    
                        // send 3 mails
                        SendNewEmail("[email protected]", "Hi", f.SendType);
                        SendNewEmail("[email protected]", "Hello", MailSendType.Normal);
                        SendNewEmail("[email protected]", "Yo", f.SendType);
    
                        // either send or don't send the orginal one
                        // by default Cancel is set to false (So by default the message will send)
    
                        // send the 3 mails and send the original one typed up by the user
                        //Cancel = false;
    
                        // send the 3 mails and do not send the original one currently typed up by the user
                       // Cancel = true;
                    }
    
            }
        }
    

    Between these 2 examples and the f.ShowDialog() setup you should be able to find the solution you seek. You can also mix and match by modifying the original email and sending additional one.