C# 启动新的 MailTo 进程和 HTML URL 编码

发布于 2024-07-16 23:18:47 字数 10761 浏览 11 评论 0原文

我为 Process 类创建了一个新的 MailTo 扩展方法,该方法只是用一个新的 ProcessStartinfo 填充 Process,其中包含所需的 mailto 参数。 我创建了一个名为 FormatMailToArgument (在最后)的方法,它将控制字符转换为其 Url 编码的等效项,并对此进行了测试,它可以工作,但是有更好的方法吗?

/// <summary>
/// <see cref="Process"/> extension methods.
/// </summary>
public static class Processes
{
    #region MailTo

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="mailMessage">The mail message.</param>
    public static void MailTo(this Process process, MailMessage mailMessage)
    {
        MailTo(
            process,
            mailMessage.To.ToDelimetedString(),
            mailMessage.CC.ToDelimetedString(),
            mailMessage.Bcc.ToDelimetedString(),
            mailMessage.Subject,
            mailMessage.Body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    public static void MailTo(this Process process, IEnumerable<string> to)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            null,
            null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="subject">The email subject.</param>
    public static void MailTo(this Process process, IEnumerable<string> to, string subject)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            subject,
            null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        string subject,
        string body)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        string subject,
        string body)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            cc.ToDelimetedString(Character.SemiColon),
            null,
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any 
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="bcc">The Bcc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        IEnumerable<string> bcc,
        string subject,
        string body)
    {
        MailTo(
            process,
            (to == null) ? null : to.ToDelimetedString(Character.SemiColon),
            (cc == null) ? null : cc.ToDelimetedString(Character.SemiColon),
            (bcc == null) ? null : bcc.ToDelimetedString(Character.SemiColon),
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="bcc">The Bcc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    /// <param name="attachmentPath">The attachment file path.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        IEnumerable<string> bcc,
        string subject,
        string body,
        string attachmentPath)
    {
        MailTo(
            process,
            (to == null) ? null : to.ToDelimetedString(Character.SemiColon),
            (cc == null) ? null : cc.ToDelimetedString(Character.SemiColon),
            (bcc == null) ? null : bcc.ToDelimetedString(Character.SemiColon),
            subject,
            body,
            attachmentPath);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any 
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses delimeted by a semi-colon.</param>
    /// <param name="cc">The Cc email addresses delimeted by a semi-colon.</param>
    /// <param name="bcc">The Bcc email addresses delimeted by a semi-colon.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(this Process process, string to, string cc, string bcc, string subject, string body)
    {
        MailTo(process, to, cc, bcc, subject, body, null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses delimeted by a semi-colon.</param>
    /// <param name="cc">The Cc email addresses delimeted by a semi-colon.</param>
    /// <param name="bcc">The Bcc email addresses delimeted by a semi-colon.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    /// <param name="attachmentPath">The attachment file path. Note: this will not work in some 
    /// email applications.</param>
    public static void MailTo(
        this Process process,
        string to,
        string cc,
        string bcc,
        string subject,
        string body,
        string attachmentPath)
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append(Uri.UriSchemeMailto + Character.Colon);
        stringBuilder.Append(FormatMailToArgument(to));

        if (!string.IsNullOrEmpty(cc) || !string.IsNullOrEmpty(bcc) ||
            !string.IsNullOrEmpty(subject) || !string.IsNullOrEmpty(body) ||
            !string.IsNullOrEmpty(attachmentPath))
        {
            stringBuilder.Append(Character.Question);

            List<string> arguments = new List<string>();

            if (!string.IsNullOrEmpty(subject))
            {
                arguments.Add("subject=" + FormatMailToArgument(subject));
            }

            if (!string.IsNullOrEmpty(body))
            {
                arguments.Add("body=" + FormatMailToArgument(body));
            }

            if (!string.IsNullOrEmpty(cc))
            {
                arguments.Add("CC=" + FormatMailToArgument(cc));
            }

            if (!string.IsNullOrEmpty(bcc))
            {
                arguments.Add("BCC=" + FormatMailToArgument(bcc));
            }

            if (!string.IsNullOrEmpty(attachmentPath))
            {
                arguments.Add("attachment=" + FormatMailToArgument(attachmentPath));
            }

            stringBuilder.Append(arguments.ToDelimetedString(Character.Ampersand));
        }

        process.StartInfo = new ProcessStartInfo(stringBuilder.ToString());
    }

    #endregion

    #region Methods

    /// <summary>
    /// Formats the mailto argument. Converts <![CDATA['%', '&', ' ', '?', '\t', '\n']]> to their 
    /// hexadecimal representation.
    /// </summary>
    /// <param name="argument">The argument.</param>
    /// <returns>The formatted argument.</returns>
    private static string FormatMailToArgument(string argument)
    {
        return argument.
            Replace(Character.Percent.ToString(), "%25").
            Replace(Character.Ampersand.ToString(), "%26").
            Replace(Character.Colon.ToString(), "%3A").
            Replace(Character.HorizontalTab.ToString(), "%0D").
            Replace(Character.NewLine.ToString(), "%0A").
            Replace(Character.Question.ToString(), "%3F").
            Replace(Character.Quote.ToString(), "%22").
            Replace(Character.Space.ToString(), "%20");
    }

    #endregion
}

I have created a new MailTo extension method for the Process class which just fills the Process with a new ProcessStartinfo which contains the required mailto arguments. I have created a method called FormatMailToArgument (Right at the end) which converts control characters to their Url Encoded equivelants and have tested this and it works but is there a better way of doing this?

/// <summary>
/// <see cref="Process"/> extension methods.
/// </summary>
public static class Processes
{
    #region MailTo

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="mailMessage">The mail message.</param>
    public static void MailTo(this Process process, MailMessage mailMessage)
    {
        MailTo(
            process,
            mailMessage.To.ToDelimetedString(),
            mailMessage.CC.ToDelimetedString(),
            mailMessage.Bcc.ToDelimetedString(),
            mailMessage.Subject,
            mailMessage.Body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    public static void MailTo(this Process process, IEnumerable<string> to)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            null,
            null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="subject">The email subject.</param>
    public static void MailTo(this Process process, IEnumerable<string> to, string subject)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            subject,
            null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        string subject,
        string body)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        string subject,
        string body)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            cc.ToDelimetedString(Character.SemiColon),
            null,
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any 
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="bcc">The Bcc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        IEnumerable<string> bcc,
        string subject,
        string body)
    {
        MailTo(
            process,
            (to == null) ? null : to.ToDelimetedString(Character.SemiColon),
            (cc == null) ? null : cc.ToDelimetedString(Character.SemiColon),
            (bcc == null) ? null : bcc.ToDelimetedString(Character.SemiColon),
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="bcc">The Bcc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    /// <param name="attachmentPath">The attachment file path.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        IEnumerable<string> bcc,
        string subject,
        string body,
        string attachmentPath)
    {
        MailTo(
            process,
            (to == null) ? null : to.ToDelimetedString(Character.SemiColon),
            (cc == null) ? null : cc.ToDelimetedString(Character.SemiColon),
            (bcc == null) ? null : bcc.ToDelimetedString(Character.SemiColon),
            subject,
            body,
            attachmentPath);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any 
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses delimeted by a semi-colon.</param>
    /// <param name="cc">The Cc email addresses delimeted by a semi-colon.</param>
    /// <param name="bcc">The Bcc email addresses delimeted by a semi-colon.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(this Process process, string to, string cc, string bcc, string subject, string body)
    {
        MailTo(process, to, cc, bcc, subject, body, null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses delimeted by a semi-colon.</param>
    /// <param name="cc">The Cc email addresses delimeted by a semi-colon.</param>
    /// <param name="bcc">The Bcc email addresses delimeted by a semi-colon.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    /// <param name="attachmentPath">The attachment file path. Note: this will not work in some 
    /// email applications.</param>
    public static void MailTo(
        this Process process,
        string to,
        string cc,
        string bcc,
        string subject,
        string body,
        string attachmentPath)
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append(Uri.UriSchemeMailto + Character.Colon);
        stringBuilder.Append(FormatMailToArgument(to));

        if (!string.IsNullOrEmpty(cc) || !string.IsNullOrEmpty(bcc) ||
            !string.IsNullOrEmpty(subject) || !string.IsNullOrEmpty(body) ||
            !string.IsNullOrEmpty(attachmentPath))
        {
            stringBuilder.Append(Character.Question);

            List<string> arguments = new List<string>();

            if (!string.IsNullOrEmpty(subject))
            {
                arguments.Add("subject=" + FormatMailToArgument(subject));
            }

            if (!string.IsNullOrEmpty(body))
            {
                arguments.Add("body=" + FormatMailToArgument(body));
            }

            if (!string.IsNullOrEmpty(cc))
            {
                arguments.Add("CC=" + FormatMailToArgument(cc));
            }

            if (!string.IsNullOrEmpty(bcc))
            {
                arguments.Add("BCC=" + FormatMailToArgument(bcc));
            }

            if (!string.IsNullOrEmpty(attachmentPath))
            {
                arguments.Add("attachment=" + FormatMailToArgument(attachmentPath));
            }

            stringBuilder.Append(arguments.ToDelimetedString(Character.Ampersand));
        }

        process.StartInfo = new ProcessStartInfo(stringBuilder.ToString());
    }

    #endregion

    #region Methods

    /// <summary>
    /// Formats the mailto argument. Converts <![CDATA['%', '&', ' ', '?', '\t', '\n']]> to their 
    /// hexadecimal representation.
    /// </summary>
    /// <param name="argument">The argument.</param>
    /// <returns>The formatted argument.</returns>
    private static string FormatMailToArgument(string argument)
    {
        return argument.
            Replace(Character.Percent.ToString(), "%25").
            Replace(Character.Ampersand.ToString(), "%26").
            Replace(Character.Colon.ToString(), "%3A").
            Replace(Character.HorizontalTab.ToString(), "%0D").
            Replace(Character.NewLine.ToString(), "%0A").
            Replace(Character.Question.ToString(), "%3F").
            Replace(Character.Quote.ToString(), "%22").
            Replace(Character.Space.ToString(), "%20");
    }

    #endregion
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

救星 2024-07-23 23:18:47

如果您的意思是有更有效的方法来转义您的电子邮件地址,那么您可以使用 System.Uri 类。

string escapedAddress = Uri.EscapeUriString("mailto:joe blogg's\r\[email protected]");
Console.WriteLine(escapedAddress);

输出:

mailto:joe%20blogg's%0D%[email protected]

您会注意到在我的示例中,单引号字符没有被转义,但这是因为它不需要出现在电子邮件地址中。

就您使用的一般方法而言,我不明白为什么您要向 Process 类添加扩展方法。 发送电子邮件并转义所有地址。 附件、服务器身份验证等。等等。为什么不只使用 System.Net.Mail 类?

If you mean is there are more efficient way to escape your email addresses then yes you could use the System.Uri class.

string escapedAddress = Uri.EscapeUriString("mailto:joe blogg's\r\[email protected]");
Console.WriteLine(escapedAddress);

Output:

mailto:joe%20blogg's%0D%[email protected]

You'll notice in my example the single quote character doesn't get escaped but that's because it's not required to be in email addresses.

As far as the general approach you have used I don't see why you would add an extension method to the Process class. To send an email and have all the address escaping. attachments, server authentication etc. etc. taken care of why not just use the System.Net.Mail classes?

鹿! 2024-07-23 23:18:47

此官方链接<中所述/a>,EscapeUriString 方法假定 stringToEscape 参数中没有转义序列。

这种方法非常适合转义 Uris,但要小心,因为目标字符串是一个 mailto: 行,可以包含许多参数(不仅是主题、正文……),显然每个参数都用一些参数分隔开转义字符...例如 &?

因此,在我使用从 @anon 注释中获取文本的 Windows 应用商店应用程序进行的测试中,该字符串不会使用 just Uri.EscapeUriString() 方法完全转义,因为它包含转义序列&

您将需要额外的手动转义才能将整个字符串作为 mailto: Uri 中的参数传递:

Uri.EscapeUriString(stringToEscape).Replace("&", "%26");

As documented in is this official link, the EscapeUriString method assumes that stringToEscape parameter has no escape sequences in it.

This method is perfect for escaping Uris, but be careful because the target string is a mailto: line that can contain many parameters (not only subject, body, ...), obviously separated each one with some escape characters...like & and ?.

So, in my tests with Windows Store Apps with text taken from @anon comment, that string will not be fully escaped using just Uri.EscapeUriString() method, because it contains the escape sequence &.

You will need an extra manual escape to get the whole string be passed as parameter in a mailto: Uri:

Uri.EscapeUriString(stringToEscape).Replace("&", "%26");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文