详解 WordPress `wp_mail()` 函数的源码:如何通过 `wp_mail_from` 和 `wp_mail_from_name` 过滤器自定义发件人信息。

咳咳,各位观众老爷,晚上好!我是你们的老朋友,Bug终结者,今天咱们聊聊WordPress里那个神出鬼没,又不得不伺候好的wp_mail()函数。

别看它名字简单,背后可藏着不少门道,尤其是想自定义发件人信息,就得跟wp_mail_fromwp_mail_from_name这两个过滤器好好打交道。今天,咱们就扒开它的源码,看看这俩过滤器是怎么发挥作用的。

一、wp_mail() 函数:初窥门径

首先,咱们先简单看看 wp_mail() 函数的基本结构。别害怕,源码其实没那么可怕,咱们一步一步来。

function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
    // (省略了大量的代码,只保留关键部分)

    // Set Content-Type if not already set.
    if ( strpos( $headers, 'Content-Type:' ) === false ) {
        $headers .= "Content-Type: text/plain; charset=" . get_bloginfo( 'charset' ) . "rn";
    }

    // Compact the input array into an associative array.
    if ( is_array( $to ) ) {
        $to = implode( ',', $to );
    }

    // Allow plugins to short-circuit the mail send.
    $phpmailer_loaded = class_exists( 'PHPMailer', false );
    $phpmailer          = new WP_PHPMailer( true ); // Passing `true` enables exceptions.

    // From email and name.  These are set later on.
    $from_email = get_option( 'admin_email' );
    $from_name  = 'WordPress';

    try {
        // Set From: header
        // Note: This must be done before other headers are set, or PHPMailer won't use the custom From.
        $phpmailer->setFrom( $from_email, $from_name, false );  // The third parameter is "auto_utf8"

        // Add all From, Reply-To and Return-Path headers
        $from = apply_filters( 'wp_mail_from', $from_email );
        $name = apply_filters( 'wp_mail_from_name', $from_name );

        try {
            $phpmailer->setFrom( $from, $name, false );
        } catch ( Exception $e ) {
            $mail_error_data['wp_mail_phpmailer_exception_set_from'][] = $e->getMessage();
            $phpmailer->setFrom( $from_email, $from_name, false );
        }

        if ( $from_email != $from ) {
            $phpmailer->addReplyTo( $from_email, $from_name );
        }
        // (省略了更多的代码)
        $sent = $phpmailer->send();

    } catch ( Exception $e ) {
        // (省略了异常处理代码)
    }

    return $sent;
}

别被一大坨代码吓到,咱们关注几个关键点:

  1. $from_email = get_option( 'admin_email' );$from_name = 'WordPress';: 默认情况下,发件人邮箱是 WordPress 后台设置的管理员邮箱,发件人名字是 "WordPress"。这俩变量决定了最初的发件人信息。

  2. apply_filters( 'wp_mail_from', $from_email );apply_filters( 'wp_mail_from_name', $from_name );: 看到了吗?这就是我们今天要讲的重点!WordPress 使用 apply_filters() 函数,将默认的发件人邮箱和名字分别传递给 'wp_mail_from''wp_mail_from_name' 过滤器。这意味着我们可以通过这两个过滤器来修改它们。

  3. $phpmailer->setFrom( $from, $name, false );: 最终,修改后的 $from (邮箱) 和 $name (名字) 会被传递给 PHPMailer 类的 setFrom() 方法,PHPMailer 才是真正负责发送邮件的幕后英雄。注意第三个参数 false,意思是禁用自动 UTF-8 编码。

二、wp_mail_from 过滤器:邮箱大变身

wp_mail_from 过滤器允许我们修改发件人的邮箱地址。 举个例子,假设你想让所有从 WordPress 发出的邮件都显示成来自 [email protected]。 你可以这样写代码:

add_filter( 'wp_mail_from', 'my_custom_mail_from' );

function my_custom_mail_from( $original_email ) {
    // 检查一下,避免影响其他插件
    if ( strpos( $_SERVER['REQUEST_URI'], 'wp-cron.php' ) !== false ) {
        return $original_email; // 如果是计划任务,保持原来的邮箱
    }
    return '[email protected]';
}

这段代码做了什么呢?

  • add_filter( 'wp_mail_from', 'my_custom_mail_from' );: 这行代码告诉 WordPress,当 wp_mail_from 过滤器被调用时,执行 my_custom_mail_from 函数。

  • my_custom_mail_from( $original_email ): 这个函数接收一个参数 $original_email,这是 WordPress 默认的发件人邮箱(通常是管理员邮箱)。函数内部,我们直接返回了 '[email protected]',覆盖了原来的值。strpos( $_SERVER['REQUEST_URI'], 'wp-cron.php' ) !== false 这段代码是为了避免影响计划任务,如果邮件是计划任务触发的,则保持原来的邮箱。

重点:

  • 过滤器函数必须接收一个参数,这个参数是原始值(在这里是原始的邮箱地址)。
  • 过滤器函数必须返回一个值,这个值将被 WordPress 使用。

三、wp_mail_from_name 过滤器:姓名大挪移

wp_mail_from_name 过滤器的作用和 wp_mail_from 类似,只不过它是用来修改发件人的名字的。 比如,你想把发件人名字改成 "Example Company",可以这样写:

add_filter( 'wp_mail_from_name', 'my_custom_mail_from_name' );

function my_custom_mail_from_name( $original_name ) {
    return 'Example Company';
}

这段代码的结构和 wp_mail_from 的例子几乎一样,只是把过滤器名字改成了 'wp_mail_from_name',并且返回了新的名字 'Example Company'

四、组合拳:邮箱和名字一起改

当然,你可以同时使用 wp_mail_fromwp_mail_from_name 过滤器,一次性修改邮箱和名字:

add_filter( 'wp_mail_from', 'my_custom_mail_from' );
add_filter( 'wp_mail_from_name', 'my_custom_mail_from_name' );

function my_custom_mail_from( $original_email ) {
    return '[email protected]';
}

function my_custom_mail_from_name( $original_name ) {
    return 'Example Company';
}

这段代码会把所有从 WordPress 发出的邮件的发件人邮箱改成 [email protected],发件人名字改成 "Example Company"。

五、更高级的用法:条件判断和动态修改

上面的例子都比较简单粗暴,直接把邮箱和名字写死了。 在实际开发中,我们可能需要根据不同的情况动态修改发件人信息。 比如,根据邮件类型或者收件人来修改发件人信息。

add_filter( 'wp_mail_from', 'my_conditional_mail_from' );
add_filter( 'wp_mail_from_name', 'my_conditional_mail_from_name' );

function my_conditional_mail_from( $original_email ) {
    // 假设我们有一个自定义字段 'email_type',用来表示邮件类型
    $email_type = get_option( 'email_type' );

    if ( $email_type == 'notification' ) {
        return '[email protected]';
    } elseif ( $email_type == 'support' ) {
        return '[email protected]';
    } else {
        return $original_email; // 默认情况,保持原来的邮箱
    }
}

function my_conditional_mail_from_name( $original_name ) {
    // 同样根据邮件类型来修改发件人名字
    $email_type = get_option( 'email_type' );

    if ( $email_type == 'notification' ) {
        return 'Notification Team';
    } elseif ( $email_type == 'support' ) {
        return 'Support Team';
    } else {
        return $original_name; // 默认情况,保持原来的名字
    }
}

在这个例子中,我们根据 get_option( 'email_type' ) 获取到的邮件类型,来动态地修改发件人邮箱和名字。如果邮件类型是 "notification",发件人邮箱就是 [email protected],名字就是 "Notification Team"。如果邮件类型是 "support",发件人邮箱就是 [email protected],名字就是 "Support Team"。 否则,就保持原来的邮箱和名字。

六、避免踩坑:一些注意事项

在使用 wp_mail_fromwp_mail_from_name 过滤器时,需要注意以下几点:

  • 插件冲突: 某些插件可能会修改 wp_mail() 函数的行为,导致你的过滤器失效。 如果遇到这种情况,需要检查一下是否有冲突的插件,或者调整过滤器的优先级。 你可以通过 add_filter() 函数的第三个参数来设置过滤器的优先级,数字越小,优先级越高。 例如:add_filter( 'wp_mail_from', 'my_custom_mail_from', 10 ); 默认优先级是 10
  • 邮件服务器限制: 有些邮件服务器可能会限制发件人邮箱的域名,如果你使用了未经授权的域名,可能会导致邮件发送失败。 确保你使用的域名是经过授权的,或者使用 SMTP 插件来配置你的邮件服务器。
  • 垃圾邮件: 如果你随意修改发件人信息,可能会被邮件服务器认为是垃圾邮件,导致邮件被拦截。 尽量使用真实的、可信的发件人信息,并且配置好 SPF、DKIM 等 DNS 记录,以提高邮件的可信度。
  • 编码问题: 如果你的发件人名字包含非 ASCII 字符,可能会出现乱码问题。 确保你的 WordPress 站点使用了 UTF-8 编码,并且在设置发件人名字时,使用 mb_encode_mimeheader() 函数进行编码。
  • 调试困难: 当邮件发送出现问题时,调试起来可能比较困难。建议安装一个邮件日志插件,记录所有发送的邮件,方便你查找问题。

七、一些实例代码,便于理解

使用场景 代码示例 说明
修改所有邮件的发件人为统一的邮箱和名称 php<br> add_filter( 'wp_mail_from', 'set_new_mail_from' );<br> function set_new_mail_from( $old ) {<br> return '[email protected]';<br> }<br><br> add_filter( 'wp_mail_from_name', 'set_new_mail_from_name' );<br> function set_new_mail_from_name( $old ) {<br> return 'Your New Name';<br> }<br> | 将所有通过 wp_mail() 发送的邮件的发件人邮箱修改为 [email protected],发件人名称修改为 Your New Name
根据收件人动态修改发件人邮箱和名称 php<br> add_filter( 'wp_mail_from', 'dynamic_mail_from' );<br> function dynamic_mail_from( $email ) {<br> global $wp_mail;<br> $recipient = $wp_mail->to;<br><br> if ( in_array( '[email protected]', $recipient ) ) {<br> return '[email protected]';<br> } elseif ( in_array( '[email protected]', $recipient ) ) {<br> return '[email protected]';<br> }<br><br> return $email;<br> }<br><br> add_filter( 'wp_mail_from_name', 'dynamic_mail_from_name' );<br> function dynamic_mail_from_name( $name ) {<br> global $wp_mail;<br> $recipient = $wp_mail->to;<br><br> if ( in_array( '[email protected]', $recipient ) ) {<br> return 'Name for User 1';<br> } elseif ( in_array( '[email protected]', $recipient ) ) {<br> return 'Name for User 2';<br> }<br><br> return $name;<br> }<br> | 根据收件人不同,动态设置发件人邮箱和名称。如果收件人包含 [email protected],则使用 [email protected]Name for User 1;如果收件人包含 [email protected],则使用 [email protected]Name for User 2
根据主题动态修改发件人邮箱和名称 php<br> add_filter( 'wp_mail_from', 'subject_based_mail_from' );<br> function subject_based_mail_from( $email ) {<br> global $wp_mail;<br> $subject = $wp_mail->subject;<br><br> if ( strpos( $subject, 'Order Confirmation' ) !== false ) {<br> return '[email protected]';<br> } elseif ( strpos( $subject, 'Support Request' ) !== false ) {<br> return '[email protected]';<br> }<br><br> return $email;<br> }<br><br> add_filter( 'wp_mail_from_name', 'subject_based_mail_from_name' );<br> function subject_based_mail_from_name( $name ) {<br> global $wp_mail;<br> $subject = $wp_mail->subject;<br><br> if ( strpos( $subject, 'Order Confirmation' ) !== false ) {<br> return 'Order Department';<br> } elseif ( strpos( $subject, 'Support Request' ) !== false ) {<br> return 'Support Team';<br> }<br><br> return $name;<br> }<br> | 根据邮件主题不同,动态设置发件人邮箱和名称。如果主题包含 Order Confirmation,则使用 [email protected]Order Department;如果主题包含 Support Request,则使用 [email protected]Support Team
结合自定义字段动态修改发件人邮箱和名称(假设使用 ACF) php<br> add_filter( 'wp_mail_from', 'acf_based_mail_from' );<br> function acf_based_mail_from( $email ) {<br> $custom_email = get_field( 'email_override', 'option' ); // 'option' 表示从 Options Page 获取<br><br> if ( $custom_email ) {<br> return $custom_email;<br> }<br><br> return $email;<br> }<br><br> add_filter( 'wp_mail_from_name', 'acf_based_mail_from_name' );<br> function acf_based_mail_from_name( $name ) {<br> $custom_name = get_field( 'name_override', 'option' ); // 'option' 表示从 Options Page 获取<br><br> if ( $custom_name ) {<br> return $custom_name;<br> }<br><br> return $name;<br> }<br> | 从 ACF Options Page 获取自定义字段 'email_override''name_override' 的值,如果存在,则用它们来覆盖发件人邮箱和名称。这允许管理员通过后台界面轻松修改发件人信息。
调试邮件发送问题 php<br> add_action( 'phpmailer_init', 'debug_phpmailer' );<br> function debug_phpmailer( $phpmailer ) {<br> $phpmailer->SMTPDebug = 2; // 开启调试模式<br> $phpmailer->Debugoutput = 'html'; // 'html', 'echo', 'error_log'<br> }<br> | 启用 PHPMailer 的调试模式,可以查看详细的 SMTP 通信过程,有助于诊断邮件发送问题。 $phpmailer->Debugoutput = 'html';将调试信息输出到 HTML 页面中。也可以设置为 'echo' 直接输出到屏幕,或者 'error_log' 写入到服务器的错误日志中。

八、总结:灵活运用,掌控邮件

wp_mail() 函数是 WordPress 发送邮件的核心,而 wp_mail_fromwp_mail_from_name 过滤器则是我们自定义发件人信息的利器。 掌握了它们,你就可以根据自己的需求,灵活地控制 WordPress 发送的邮件,让邮件更加个性化,更加专业。

好了,今天的讲座就到这里。 希望大家能够学有所获,在 WordPress 的世界里玩得更开心! 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注