flarum / framework

Simple forum software for building great communities.
http://flarum.org/
6.27k stars 826 forks source link

feat: notification unsubscribe & email overhaul with HTML multipart #3872

Closed imorland closed 11 months ago

imorland commented 1 year ago

Removals, changes & additions

SendRawEmailJob is removed, and replaced with SendInformationalEmailJob.

Usage example:

$queue->push(new SendInformationalEmailJob(email: 'user@example.com', subject: 'emailSubject', forumTitle: 'forumTitle', bodyTitle: 'informationHeader'));

Outgoing email format

image

By setting the mail_format to text, you're instructing Flarum to only send emails in the plain text format, disregarding the HTML version and multipart option. Adjust this setting according to your needs, but it is recommended to leave it at it's default.

Notification templates

Flarum now has two types of notifications/emails. Notification and Informational. Informational emails are things like, password confirm, test, etc. Basically an email that does not require (or should not have) an unsubscribe link and are classified as "essential" or "service" mail.

For all other emails, this should probably fall into the Notification type. These notifications automatically generate an unsubscribe link and this is rendered in the footer of the email (both HTML and plain).

For this reason, when constructing blade templates for emails, you should extend one of the base types:

HTML

When rendering content and/or preview content in a HTML template, it must be wrapped in the utility $formatter->convert($yourContent) For example:

{!! $formatter->convert($translator->trans('my_key')) !!}

or, for a Post object:

{!! $blueprint->formatContent() !!}
Plain

Both templates allow for sectioned data to be rendered. It is no longer required to include the user greeting, this is now contained in a translation key core.email.greeting, for example "Hey username".

@section('content')
{YOUR_CONTENT_HERE}
@endsection
@section('contentPreview')
{YOUR_CONTENT_HERE}
@endsection

contentPreview is optional, if your blade template does not provide it, nothing will be rendered in it's template area. content is always required.

Emails now also have a "signoff" section. Here, the translation key core.email.signoff by default will render "The {YOUR_FORUM_NAME} team".

Should you wish to disable either the greeting or signoff, this can be done on a template by template method:

@extends('flarum.forum::email.html.notification.base', ['greeting' => false, 'signoff' => false])


Screenshots

Example informational email (email test): image

Example notification email (desktop): image

After clicking to unsubscribe from a notification type, the user is asked to confirm: image

...

Changes:
imorland commented 1 year ago

I like this a lot, great job! My only thought: maybe we should have the unsubscribe controller redirect to the settings page, with a payload in the URL that would trigger an alert / popup / etc?

I did consider that at one point, however that would also require the user to be either logged in, or be bounced thru an auth flow before bing able to present their settings.

My understanding for Unsubscribe-List is that it should ideally be 1-click. Perhaps we can do this by using the one-time token already generated for the unsubscribe to log the user in? 🤔 Then again, that would also be a security risk, as anyone with that email would then be able to access the account (if the token has not already been used).

askvortsov1 commented 1 year ago

That's a good point. I think "unsubscribe on click + link to settings page" is a good compromise.

Instead of unsubscribing on the GET request, maybe that page should be a form (autosubmitted via JS), that pings a POST endpoint?

imorland commented 1 year ago

Instead of unsubscribing on the GET request, maybe that page should be a form (autosubmitted via JS), that pings a POST endpoint?

And if JS is disabled/not available in the email client webview/whatever?

askvortsov1 commented 1 year ago

Instead of unsubscribing on the GET request, maybe that page should be a form (autosubmitted via JS), that pings a POST endpoint?

And if JS is disabled/not available in the email client webview/whatever?

Then show a button. Most unsubscribe links I've experience ask you to click a button to confirm; the annoying ones are where you need to click a bunch of checkboxes. What I'm proposing is pretty much what's discussed in the comment thread started by @luceos

imorland commented 1 year ago

Yeah, sorry I was having a "moment" 🙈

I'm already working on this, should be ready shortly