1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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>Welcome to #{instance_name()}!</h3>
85 <p>Email confirmation is required to activate the account.</p>
86 <p>Click the following link to proceed: <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)
110 Email used in digest email notifications
111 Includes Mentions and New Followers data
112 If there are no mentions (even when new followers exist), the function will return nil
114 @spec digest_email(User.t()) :: Swoosh.Email.t() | nil
115 def digest_email(user) do
116 notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
120 |> Enum.filter(&(&1.activity.data["type"] == "Create"))
121 |> Enum.map(fn notification ->
122 object = Pleroma.Object.normalize(notification.activity)
124 if not is_nil(object) do
125 object = update_in(object.data["content"], &format_links/1)
130 from: User.get_by_ap_id(notification.activity.actor)
138 |> Enum.filter(&(&1.activity.data["type"] == "Follow"))
139 |> Enum.map(fn notification ->
140 from = User.get_by_ap_id(notification.activity.actor)
142 if not is_nil(from) do
145 object: Pleroma.Object.normalize(notification.activity),
146 from: User.get_by_ap_id(notification.activity.actor)
152 unless Enum.empty?(mentions) do
153 styling = Config.get([__MODULE__, :styling])
154 logo = Config.get([__MODULE__, :logo])
157 instance: instance_name(),
160 followers: followers,
161 unsubscribe_link: unsubscribe_url(user, "digest"),
167 Path.join(:code.priv_dir(:pleroma), "static/static/logo.png")
169 Path.join(Config.get([:instance, :static_dir]), logo)
173 |> to(recipient(user))
175 |> subject("Your digest from #{instance_name()}")
177 |> render_body("digest.html", html_data)
178 |> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.png", type: :inline))
182 defp format_links(str) do
183 re = ~r/<a.+href=['"].*>/iU
184 %{link_color: color} = Config.get([__MODULE__, :styling])
186 Regex.replace(re, str, fn link ->
187 String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
192 Generate unsubscribe link for given user and notifications type.
193 The link contains JWT token with the data, and subscription can be modified without
196 @spec unsubscribe_url(User.t(), String.t()) :: String.t()
197 def unsubscribe_url(user, notifications_type) do
199 %{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
200 |> Pleroma.JWT.generate_and_sign!()
203 Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)