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"
8 use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email}
12 alias Pleroma.Web.Endpoint
13 alias Pleroma.Web.Router
15 import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
17 defp recipient(email, nil), do: email
18 defp recipient(email, name), do: {name, email}
19 defp recipient(%User{} = user), do: recipient(user.email, user.name)
21 @spec welcome(User.t(), map()) :: Swoosh.Email.t()
22 def welcome(user, opts \\ %{}) do
24 |> to(recipient(user))
25 |> from(Map.get(opts, :sender, sender()))
26 |> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
27 |> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
28 |> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
31 def password_reset_email(user, token) when is_binary(token) do
32 password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
35 <h3>Reset your password at #{instance_name()}</h3>
36 <p>Someone has requested password change for your account at #{instance_name()}.</p>
37 <p>If it was you, visit the following link to proceed: <a href="#{password_reset_url}">reset password</a>.</p>
38 <p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
42 |> to(recipient(user))
44 |> subject("Password reset")
45 |> html_body(html_body)
48 def user_invitation_email(
50 %Pleroma.UserInviteToken{} = user_invite_token,
55 Router.Helpers.redirect_url(
58 user_invite_token.token
62 <h3>You are invited to #{instance_name()}</h3>
63 <p>#{user.name} invites you to join #{instance_name()}, an instance of Pleroma federated social networking platform.</p>
64 <p>Click the following link to register: <a href="#{registration_url}">accept invitation</a>.</p>
68 |> to(recipient(to_email, to_name))
70 |> subject("Invitation to #{instance_name()}")
71 |> html_body(html_body)
74 def account_confirmation_email(user) do
76 Router.Helpers.confirm_email_url(
80 to_string(user.confirmation_token)
84 <h3>Thank you for registering on #{instance_name()}</h3>
85 <p>Email confirmation is required to activate the account.</p>
86 <p>Please click the following link to <a href="#{confirmation_url}">activate your account</a>.</p>
90 |> to(recipient(user))
92 |> subject("#{instance_name()} account confirmation")
93 |> html_body(html_body)
96 def approval_pending_email(user) do
98 <h3>Awaiting Approval</h3>
99 <p>Your account at #{instance_name()} is being reviewed by staff. You will receive another email once your account is approved.</p>
103 |> to(recipient(user))
105 |> subject("Your account is awaiting approval")
106 |> html_body(html_body)
109 def successful_registration_email(user) do
111 <h3>Hello @#{user.nickname},</h3>
112 <p>Your account at #{instance_name()} has been registered successfully.</p>
113 <p>No further action is required to activate your account.</p>
117 |> to(recipient(user))
119 |> subject("Account registered on #{instance_name()}")
120 |> html_body(html_body)
124 Email used in digest email notifications
125 Includes Mentions and New Followers data
126 If there are no mentions (even when new followers exist), the function will return nil
128 @spec digest_email(User.t()) :: Swoosh.Email.t() | nil
129 def digest_email(user) do
130 notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
134 |> Enum.filter(&(&1.activity.data["type"] == "Create"))
135 |> Enum.map(fn notification ->
136 object = Pleroma.Object.normalize(notification.activity, fetch: false)
138 if not is_nil(object) do
139 object = update_in(object.data["content"], &format_links/1)
144 from: User.get_by_ap_id(notification.activity.actor)
152 |> Enum.filter(&(&1.activity.data["type"] == "Follow"))
153 |> Enum.map(fn notification ->
154 from = User.get_by_ap_id(notification.activity.actor)
156 if not is_nil(from) do
159 object: Pleroma.Object.normalize(notification.activity, fetch: false),
160 from: User.get_by_ap_id(notification.activity.actor)
166 unless Enum.empty?(mentions) do
167 styling = Config.get([__MODULE__, :styling])
168 logo = Config.get([__MODULE__, :logo])
171 instance: instance_name(),
174 followers: followers,
175 unsubscribe_link: unsubscribe_url(user, "digest"),
181 Path.join(:code.priv_dir(:pleroma), "static/static/logo.svg")
183 Path.join(Config.get([:instance, :static_dir]), logo)
187 |> to(recipient(user))
189 |> subject("Your digest from #{instance_name()}")
191 |> render_body("digest.html", html_data)
192 |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
196 defp format_links(str) do
197 re = ~r/<a.+href=['"].*>/iU
198 %{link_color: color} = Config.get([__MODULE__, :styling])
200 Regex.replace(re, str, fn link ->
201 String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
206 Generate unsubscribe link for given user and notifications type.
207 The link contains JWT token with the data, and subscription can be modified without
210 @spec unsubscribe_url(User.t(), String.t()) :: String.t()
211 def unsubscribe_url(user, notifications_type) do
213 %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
214 |> Pleroma.JWT.generate_and_sign!()
217 Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)
220 def backup_is_ready_email(backup, admin_user_id \\ nil) do
221 %{user: user} = Pleroma.Repo.preload(backup, :user)
222 download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
225 if is_nil(admin_user_id) do
227 <p>You requested a full backup of your Pleroma account. It's ready for download:</p>
228 <p><a href="#{download_url}">#{download_url}</a></p>
231 admin = Pleroma.Repo.get(User, admin_user_id)
234 <p>Admin @#{admin.nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
235 <p><a href="#{download_url}">#{download_url}</a></p>
240 |> to(recipient(user))
242 |> subject("Your account archive is ready")
243 |> html_body(html_body)