VSTO 从 Outlook 中的自定义表单按钮发送电子邮件

VSTO send email from custom Form button in Outlook

我的目标,用户想发送一封新邮件,填写完(.TO.CC.Body等)点击发送按钮会显示一个客户Form 发送选项所在的位置。一种选择是在用户创建电子邮件时发送电子邮件(正常 send 按钮功能)。 是否知道如何将 ItemSend 功能分配给自定义表单中的按钮?

ThisAddIn.cs -> 打开自定义表单

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 -> 自定义发送按钮,

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

    }

更新(所有答案聚集在一起,使这项工作有效)

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 += "ad@server.xyz";
                mailItem.HTMLBody += @"<b>Some bold text at the end :)</b>";
                mailItem.HTMLBody += @"1233";
                return false; // send the mail

            case MailSendType.WithCoupon:
                mailItem.CC += "coupon@server.xyz";
                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可以设置在Properties -> Behavior -> DialogResult -> OK, Cancel, Abort等

我可以考虑 3 种可能的情况:

  1. 按发送 > 弹出表单 > Select 表单上的选项 > 修改电子邮件内容 > 发送电子邮件
  2. 按发送 > 弹出表单 > 表单上的 Select 选项 > 创建并发送新电子邮件(发送 1 封或多封新电子邮件)(丢弃旧电子邮件) >发送电子邮件
  3. 按发送 > 弹出表单 > 表单上的 Select 选项 > 创建并发送新电子邮件(发送 1 封或多封新电子邮件)(发送旧电子邮件) >发送电子邮件

请注意,一旦修改邮件内容就意味着修改所有内容。更改发件人更改主题等。因此,如果您想创建一封新电子邮件并丢弃旧电子邮件,选项 1 仍然可以完全操纵原始电子邮件。

允许用户select相关选项的对话框。

注意:放置表单按钮时,请确保在属性检查器的行为下设置 DialogResult 选项。这允许在单击自动关闭并从对话框返回的按钮之一后返回 DialogResult:OK

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;
    }
}

选项 1:仅修改电子邮件的内容

注意显示 f.ShowDialog() 而不是 f.Show() 这会阻止当前线程继续发送操作并等待用户 select 表单上的按钮。对话框中的 f.SendType 已设置并用于指示用户 select 编辑了哪个选项。使用 ProcessEmail 可以操纵电子邮件,并且 return false 会导致在 false 向下传播到父函数 Cancel = false 时发送被操纵的电子邮件(不要取消发送)。

    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 += "ad@server.xyz";
                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 += "coupon@server.xyz";
                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
        }
    }

选项 2/3 发送新电子邮件

此方法重点介绍了如何在 Outlook 中发送新电子邮件。注意:已测试使用 MailItem.Send() 发送电子邮件并且它不会再次调用 Application_ItemSend

    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("admin1@server.xyz", "Hi", f.SendType);
                    SendNewEmail("admin2@server.xyz", "Hello", MailSendType.Normal);
                    SendNewEmail("admin3@server.xyz", "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;
                }

        }
    }

在这 2 个示例和 f.ShowDialog() 设置之间,您应该能够找到您寻求的解决方案。您还可以通过修改原始电子邮件并发送额外的电子邮件来混合搭配。