代码之家  ›  专栏  ›  技术社区  ›  checker284

Laravel 5.6:如何发送电子邮件,客户会将其显示为线程/对话?

  •  1
  • checker284  · 技术社区  · 6 年前

    我的Laravel应用程序包含一个票据系统,它发送电子邮件通知。

    所有电子邮件都是这样建立和发送的:

    public function build()
    {
        $email_from_name = "Support - " . config('app.name');
        $subject = "[" . $this->ticket->id . "] " . $this->ticket->subject . " - " . config('app.name');
    
        return $this->from('support@example.com', $email_from_name)
                        ->subject($subject)
                        ->markdown('emails.customer.ticket.comment_added')
                            ->with([
                                'nickname' => $this->user->nickname,
                                'ticket_id' => $this->ticket->id,
                                'ticket_subject' => $this->ticket->subject,
                                'ticket_text' => $this->ticket_comments->text,
                            ]);
    }
    

    不幸的是,当我收到多封电子邮件时,没有电子邮件客户端(Outlook、Thunderbird、RoundCube等)将这些电子邮件显示为线程/会话。所有客户端都将每个电子邮件显示为“新电子邮件”线程/对话。

    什么规定,有些电子邮件是一个线程/对话,有些不是?如何告诉我的Laravel应用程序,这些电子邮件是一个线程/对话?

    我想,它只需要是同一个邮件主题,但不起作用。

    2 回复  |  直到 6 年前
        1
  •  1
  •   checker284    6 年前

    感谢@yeeoow提供有关 RFC 2822 标准: The References and In-Reply-To headers must be set in compliance with the RFC 2822 standard.

    基于这些信息,我检查了一些其他的电子邮件线程/对话,这些都是我的。所有这些都使用了 References In-Reply-To

    由于事实上,我们需要参考旧的电子邮件,我们需要一张桌子,在那里我们可以存储 Message-ID 每封发送的电子邮件。我已经创建了这个表:

    // Table: ticket_message_ids
    public function up()
    {
        Schema::create('ticket_message_ids', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('ticket_id')->unsigned();
            $table->integer('reference_id')->unsigned(); // Optional; You may remove it or make it ->nullable()
            $table->string('message_id');
            $table->timestamps();
        });
    }
    

    有了这张桌子,我们就可以存储 消息ID 每个发送的电子邮件,并可以引用它所属的票据。这将有助于我们以后也只与 消息ID 与这张票相关-否则,我们将在同一个电子邮件线程中混合不同的票历史记录。

    进入 reference_id 字段,您可以选择存储任务的关联ID:

    • 已添加票据文本
    • 已执行的票据操作(例如,支持者、优先级、标题或状态已更改)

    在你的邮件(如 app\Mail\TicketTextAdded.php ,现在可以添加代码部分 $this->withSwiftMessage() {} 进入你的 build() 捕捉电流的功能 消息ID 在此新邮件中,引用之前的所有其他电子邮件以及存储新邮件ID `:

    public function build()
    {
        $email_from_name = "Support - " . config('app.name');
        $subject = "[" . $this->ticket->id . "] " . $this->ticket->subject . " - " . config('app.name');
    
        $email = $this->from('support@example.com', $email_from_name)
                        ->subject($subject)
                        ->markdown('emails.customer.ticket.comment_added')
                            ->with([
                                'nickname' => $this->user->nickname,
                                'ticket_id' => $this->ticket->id,
                                'ticket_subject' => $this->ticket->subject,
                                'ticket_text' => $this->ticket_comments->text,
                            ]);
    
        // Access underlaying Swift message
        $this->withSwiftMessage(function ($swiftmessage) {
            // Get all Message-IDs associated to this specific ticket
            $message_ids = TicketMessageIds::where('ticket_id', '=', $this->ticket->id)->get();
    
            // Build RFC2822 conform 'References' header
            // Example: 'References: <4bcf5a806f795b86fb2ba7238c78983c@swift.generated> <ab7898365c4aa91bfe010d4e1e8da377@swift.generated>'
            $header_references = "";            
            foreach($message_ids as $message_id) {
                if(empty($header_references)) {
                    $header_references = $message_id->message_id;
                } else {
                    $header_references = $header_references . " " . $message_id->message_id;
                }
            }
    
            // Build RFC2822 conform 'In-Reply-To' header
            // Example: 'In-Reply-To: <ab7898365c4aa91bfe010d4e1e8da377@swift.generated>'
            $header_in_reply_to = TicketMessageIds::where('ticket_id', '=', $this->ticket->id)->orderBy('id', 'DESC')->get(['message_id'])->first()->message_id;
    
            // Add required custom headers with above values
            $headers = $swiftmessage->getHeaders();
            // 'X-Mailer' header is not required for this purpose
            // This header sets only a name for the client, which sent this message (typical values: Outlook 2016, PHPMailer v6.0.5,...)
            $headers->addTextHeader('X-Mailer', config('app.name') . ' (' . config('app.url') . ')');
            if(!empty($header_references)) {
                $headers->addTextHeader('References', $header_references);
            }
            $headers->addTextHeader('In-Reply-To', $header_in_reply_to);
    
            TicketMessageIds::create([
                'ticket_id' => $this->ticket->id,
                'message_id' => '<'.$swiftmessage->getId().'>'
            ]);
        });
    
        return $email;
    }
    

    仅供参考:您也可以更改 消息ID 在这里,我们已经设置了自定义头,但这需要符合相关的RFC文档:

    $msgId = $swiftmessage->getHeaders()->get('Message-ID');
    $msgId->setId(time() . '.' . uniqid('thing') . '@example.org');
    

    更多信息: https://swiftmailer.symfony.com/docs/headers.html#id-headers

    希望我能帮助其他人了解这些信息。:)

        2
  •  -1
  •   alberto-bottarini    6 年前

    线程由电子邮件客户端自动创建。 你什么都做不了

    推荐文章