1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Emails.UserEmail do
6 @moduledoc "User emails"
10 alias Pleroma.Web.Endpoint
11 alias Pleroma.Web.Router
14 import Phoenix.Swoosh, except: [render_body: 3]
15 import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
17 def render_body(email, template, assigns \\ %{}) do
19 |> put_new_layout({Pleroma.Web.LayoutView, :email})
20 |> put_new_view(Pleroma.Web.EmailView)
21 |> Phoenix.Swoosh.render_body(template, assigns)
24 defp recipient(email, nil), do: email
25 defp recipient(email, name), do: {name, email}
26 defp recipient(%User{} = user), do: recipient(user.email, user.name)
28 @spec welcome(User.t(), map()) :: Swoosh.Email.t()
29 def welcome(user, opts \\ %{}) do
31 |> to(recipient(user))
32 |> from(Map.get(opts, :sender, sender()))
33 |> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
34 |> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
35 |> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
38 def password_reset_email(user, token) when is_binary(token) do
39 password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
42 <h3>Reset your password at #{instance_name()}</h3>
43 <p>Someone has requested password change for your account at #{instance_name()}.</p>
44 <p>If it was you, visit the following link to proceed: <a href="#{password_reset_url}">reset password</a>.</p>
45 <p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
49 |> to(recipient(user))
51 |> subject("Password reset")
52 |> html_body(html_body)
55 def user_invitation_email(
57 %Pleroma.UserInviteToken{} = user_invite_token,
62 Router.Helpers.redirect_url(
65 user_invite_token.token
69 <h3>You are invited to #{instance_name()}</h3>
70 <p>#{user.name} invites you to join #{instance_name()}, an instance of Pleroma federated social networking platform.</p>
71 <p>Click the following link to register: <a href="#{registration_url}">accept invitation</a>.</p>
75 |> to(recipient(to_email, to_name))
77 |> subject("Invitation to #{instance_name()}")
78 |> html_body(html_body)
81 def account_confirmation_email(user) do
83 Router.Helpers.confirm_email_url(
87 to_string(user.confirmation_token)
91 <h3>Thank you for registering on #{instance_name()}</h3>
92 <p>Email confirmation is required to activate the account.</p>
93 <p>Please click the following link to <a href="#{confirmation_url}">activate your account</a>.</p>
97 |> to(recipient(user))
99 |> subject("#{instance_name()} account confirmation")
100 |> html_body(html_body)
103 def approval_pending_email(user) do
105 <h3>Awaiting Approval</h3>
106 <p>Your account at #{instance_name()} is being reviewed by staff. You will receive another email once your account is approved.</p>
110 |> to(recipient(user))
112 |> subject("Your account is awaiting approval")
113 |> html_body(html_body)
116 def successful_registration_email(user) do
118 <h3>Hello @#{user.nickname},</h3>
119 <p>Your account at #{instance_name()} has been registered successfully.</p>
120 <p>No further action is required to activate your account.</p>
124 |> to(recipient(user))
126 |> subject("Account registered on #{instance_name()}")
127 |> html_body(html_body)
131 Email used in digest email notifications
132 Includes Mentions and New Followers data
133 If there are no mentions (even when new followers exist), the function will return nil
135 @spec digest_email(User.t()) :: Swoosh.Email.t() | nil
136 def digest_email(user) do
137 notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
141 |> Enum.filter(&(&1.activity.data["type"] == "Create"))
142 |> Enum.map(fn notification ->
143 object = Pleroma.Object.normalize(notification.activity, fetch: false)
145 if not is_nil(object) do
146 object = update_in(object.data["content"], &format_links/1)
151 from: User.get_by_ap_id(notification.activity.actor)
159 |> Enum.filter(&(&1.activity.data["type"] == "Follow"))
160 |> Enum.map(fn notification ->
161 from = User.get_by_ap_id(notification.activity.actor)
163 if not is_nil(from) do
166 object: Pleroma.Object.normalize(notification.activity, fetch: false),
167 from: User.get_by_ap_id(notification.activity.actor)
173 unless Enum.empty?(mentions) do
174 styling = Config.get([__MODULE__, :styling])
175 logo = Config.get([__MODULE__, :logo])
178 instance: instance_name(),
181 followers: followers,
182 unsubscribe_link: unsubscribe_url(user, "digest"),
188 Path.join(:code.priv_dir(:pleroma), "static/static/logo.svg")
190 Path.join(Config.get([:instance, :static_dir]), logo)
194 |> to(recipient(user))
196 |> subject("Your digest from #{instance_name()}")
198 |> render_body("digest.html", html_data)
199 |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
203 defp format_links(str) do
204 re = ~r/<a.+href=['"].*>/iU
205 %{link_color: color} = Config.get([__MODULE__, :styling])
207 Regex.replace(re, str, fn link ->
208 String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
213 Generate unsubscribe link for given user and notifications type.
214 The link contains JWT token with the data, and subscription can be modified without
217 @spec unsubscribe_url(User.t(), String.t()) :: String.t()
218 def unsubscribe_url(user, notifications_type) do
220 %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
221 |> Pleroma.JWT.generate_and_sign!()
224 Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)
227 def backup_is_ready_email(backup, admin_user_id \\ nil) do
228 %{user: user} = Pleroma.Repo.preload(backup, :user)
229 download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
232 if is_nil(admin_user_id) do
234 <p>You requested a full backup of your Pleroma account. It's ready for download:</p>
235 <p><a href="#{download_url}">#{download_url}</a></p>
238 admin = Pleroma.Repo.get(User, admin_user_id)
241 <p>Admin @#{admin.nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
242 <p><a href="#{download_url}">#{download_url}</a></p>
247 |> to(recipient(user))
249 |> subject("Your account archive is ready")
250 |> html_body(html_body)