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}
13 alias Pleroma.Web.Endpoint
14 alias Pleroma.Web.Router
16 import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
18 defp recipient(email, nil), do: email
19 defp recipient(email, name), do: {name, email}
20 defp recipient(%User{} = user), do: recipient(user.email, user.name)
22 @spec welcome(User.t(), map()) :: Swoosh.Email.t()
23 def welcome(user, opts \\ %{}) do
25 |> to(recipient(user))
26 |> from(Map.get(opts, :sender, sender()))
27 |> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
28 |> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
29 |> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
32 def password_reset_email(user, token) when is_binary(token) do
33 password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
36 <h3>Reset your password at #{instance_name()}</h3>
37 <p>Someone has requested password change for your account at #{instance_name()}.</p>
38 <p>If it was you, visit the following link to proceed: <a href="#{password_reset_url}">reset password</a>.</p>
39 <p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
43 |> to(recipient(user))
45 |> subject("Password reset")
46 |> html_body(html_body)
47 |> text_body(HTML.strip_tags(html_body))
50 def user_invitation_email(
52 %Pleroma.UserInviteToken{} = user_invite_token,
57 Router.Helpers.redirect_url(
60 user_invite_token.token
64 <h3>You are invited to #{instance_name()}</h3>
65 <p>#{user.name} invites you to join #{instance_name()}, an instance of Pleroma federated social networking platform.</p>
66 <p>Click the following link to register: <a href="#{registration_url}">accept invitation</a>.</p>
70 |> to(recipient(to_email, to_name))
72 |> subject("Invitation to #{instance_name()}")
73 |> html_body(html_body)
74 |> text_body(HTML.strip_tags(html_body))
77 def account_confirmation_email(user) do
79 Router.Helpers.confirm_email_url(
83 to_string(user.confirmation_token)
87 <h3>Thank you for registering on #{instance_name()}</h3>
88 <p>Email confirmation is required to activate the account.</p>
89 <p>Please click the following link to <a href="#{confirmation_url}">activate your account</a>.</p>
93 |> to(recipient(user))
95 |> subject("#{instance_name()} account confirmation")
96 |> html_body(html_body)
97 |> text_body(HTML.strip_tags(html_body))
100 def approval_pending_email(user) do
102 <h3>Awaiting Approval</h3>
103 <p>Your account at #{instance_name()} is being reviewed by staff. You will receive another email once your account is approved.</p>
107 |> to(recipient(user))
109 |> subject("Your account is awaiting approval")
110 |> html_body(html_body)
111 |> text_body(HTML.strip_tags(html_body))
114 def successful_registration_email(user) do
116 <h3>Hello @#{user.nickname}</h3>
117 <p>Your account at #{instance_name()} has been registered successfully.</p>
118 <p>No further action is required to activate your account.</p>
122 |> to(recipient(user))
124 |> subject("Account registered on #{instance_name()}")
125 |> html_body(html_body)
126 |> text_body(HTML.strip_tags(html_body))
130 Email used in digest email notifications
131 Includes Mentions and New Followers data
132 If there are no mentions (even when new followers exist), the function will return nil
134 @spec digest_email(User.t()) :: Swoosh.Email.t() | nil
135 def digest_email(user) do
136 notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
140 |> Enum.filter(&(&1.activity.data["type"] == "Create"))
141 |> Enum.map(fn notification ->
142 object = Pleroma.Object.normalize(notification.activity, fetch: false)
144 if not is_nil(object) do
145 object = update_in(object.data["content"], &format_links/1)
150 from: User.get_by_ap_id(notification.activity.actor)
158 |> Enum.filter(&(&1.activity.data["type"] == "Follow"))
159 |> Enum.map(fn notification ->
160 from = User.get_by_ap_id(notification.activity.actor)
162 if not is_nil(from) do
165 object: Pleroma.Object.normalize(notification.activity, fetch: false),
166 from: User.get_by_ap_id(notification.activity.actor)
172 unless Enum.empty?(mentions) do
173 styling = Config.get([__MODULE__, :styling])
174 logo = Config.get([__MODULE__, :logo])
177 instance: instance_name(),
180 followers: followers,
181 unsubscribe_link: unsubscribe_url(user, "digest"),
187 Path.join(:code.priv_dir(:pleroma), "static/static/logo.svg")
189 Path.join(Config.get([:instance, :static_dir]), logo)
193 |> to(recipient(user))
195 |> subject("Your digest from #{instance_name()}")
197 |> render_body("digest.html", html_data)
198 |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
202 defp format_links(str) do
203 re = ~r/<a.+href=['"].*>/iU
204 %{link_color: color} = Config.get([__MODULE__, :styling])
206 Regex.replace(re, str, fn link ->
207 String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
212 Generate unsubscribe link for given user and notifications type.
213 The link contains JWT token with the data, and subscription can be modified without
216 @spec unsubscribe_url(User.t(), String.t()) :: String.t()
217 def unsubscribe_url(user, notifications_type) do
219 %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
220 |> Pleroma.JWT.generate_and_sign!()
223 Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)
226 def backup_is_ready_email(backup, admin_user_id \\ nil) do
227 %{user: user} = Pleroma.Repo.preload(backup, :user)
228 download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
231 if is_nil(admin_user_id) do
233 <p>You requested a full backup of your Pleroma account. It's ready for download:</p>
234 <p><a href="#{download_url}">#{download_url}</a></p>
237 admin = Pleroma.Repo.get(User, admin_user_id)
240 <p>Admin @#{admin.nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
241 <p><a href="#{download_url}">#{download_url}</a></p>
246 |> to(recipient(user))
248 |> subject("Your account archive is ready")
249 |> html_body(html_body)
250 |> text_body(HTML.strip_tags(html_body))