diff --git a/lib/plausible/imported/csv_importer.ex b/lib/plausible/imported/csv_importer.ex index 3f7f8100a3d7..12d4fb41b7a2 100644 --- a/lib/plausible/imported/csv_importer.ex +++ b/lib/plausible/imported/csv_importer.ex @@ -13,7 +13,7 @@ defmodule Plausible.Imported.CSVImporter do def label(), do: "CSV" @impl true - def email_template(), do: "csv_import.html" + def email_template(), do: :csv_import @impl true def parse_args(%{"uploads" => uploads, "storage" => storage}) do diff --git a/lib/plausible/imported/google_analytics4.ex b/lib/plausible/imported/google_analytics4.ex index 0b72c7a3f9ce..e4689da36b08 100644 --- a/lib/plausible/imported/google_analytics4.ex +++ b/lib/plausible/imported/google_analytics4.ex @@ -17,7 +17,7 @@ defmodule Plausible.Imported.GoogleAnalytics4 do def label(), do: "Google Analytics 4" @impl true - def email_template(), do: "google_analytics_import.html" + def email_template(), do: :google_analytics_import @impl true def before_start(site_import, opts) do diff --git a/lib/plausible/imported/importer.ex b/lib/plausible/imported/importer.ex index f8a20e208505..826b947e8b4b 100644 --- a/lib/plausible/imported/importer.ex +++ b/lib/plausible/imported/importer.ex @@ -102,7 +102,7 @@ defmodule Plausible.Imported.Importer do @callback name() :: atom() @callback label() :: String.t() - @callback email_template() :: String.t() + @callback email_template() :: atom | String.t() @callback parse_args(map()) :: Keyword.t() @callback import_data(SiteImport.t(), Keyword.t()) :: :ok | {:error, any()} | {:error, any(), Keyword.t()} diff --git a/lib/plausible/imported/noop_importer.ex b/lib/plausible/imported/noop_importer.ex index 01adeccc931d..6a6d60b4a52f 100644 --- a/lib/plausible/imported/noop_importer.ex +++ b/lib/plausible/imported/noop_importer.ex @@ -13,7 +13,7 @@ defmodule Plausible.Imported.NoopImporter do # reusing existing template from another source @impl true - def email_template(), do: "google_analytics_import.html" + def email_template(), do: :google_analytics_import @impl true def parse_args(opts), do: opts diff --git a/lib/plausible/imported/universal_analytics.ex b/lib/plausible/imported/universal_analytics.ex index 031d7a56c409..ccaa9438e7d6 100644 --- a/lib/plausible/imported/universal_analytics.ex +++ b/lib/plausible/imported/universal_analytics.ex @@ -14,7 +14,7 @@ defmodule Plausible.Imported.UniversalAnalytics do def label(), do: "Google Analytics" @impl true - def email_template(), do: "google_analytics_import.html" + def email_template(), do: :google_analytics_import @impl true def parse_args( diff --git a/lib/plausible_web/email.ex b/lib/plausible_web/email.ex index b6330ea20e41..2b8c95b83a12 100644 --- a/lib/plausible_web/email.ex +++ b/lib/plausible_web/email.ex @@ -12,7 +12,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("activation-email") |> subject("#{code} is your Plausible email verification code") - |> render("activation_email.html", user: user, code: code) + |> render(:activation_email, user: user, code: code) end def welcome_email(user) do @@ -20,7 +20,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("welcome-email") |> subject("Welcome to Plausible") - |> render("welcome_email.html", user: user) + |> render(:welcome_email, user: user) end def create_site_email(user) do @@ -28,7 +28,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("create-site-email") |> subject("Your Plausible setup: Add your website details") - |> render("create_site_email.html", user: user) + |> render(:create_site_email, user: user) end def site_setup_help(user, site) do @@ -36,7 +36,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("help-email") |> subject("Your Plausible setup: Waiting for the first page views") - |> render("site_setup_help_email.html", + |> render(:site_setup_help_email, user: user, site: site ) @@ -47,7 +47,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("setup-success-email") |> subject("Plausible is now tracking your website stats") - |> render("site_setup_success_email.html", + |> render(:site_setup_success_email, user: user, site: site ) @@ -58,7 +58,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("check-stats-email") |> subject("Check your Plausible website stats") - |> render("check_stats_email.html", user: user) + |> render(:check_stats_email, user: user) end def password_reset_email(email, reset_link) do @@ -66,7 +66,7 @@ defmodule PlausibleWeb.Email do |> to(email) |> tag("password-reset-email") |> subject("Plausible password reset") - |> render("password_reset_email.html", reset_link: reset_link) + |> render(:password_reset_email, reset_link: reset_link) end def two_factor_enabled_email(user) do @@ -74,7 +74,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("two-factor-enabled-email") |> subject("Plausible Two-Factor Authentication enabled") - |> render("two_factor_enabled_email.html", user: user) + |> render(:two_factor_enabled_email, user: user) end def two_factor_disabled_email(user) do @@ -82,7 +82,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("two-factor-disabled-email") |> subject("Plausible Two-Factor Authentication disabled") - |> render("two_factor_disabled_email.html", user: user) + |> render(:two_factor_disabled_email, user: user) end def trial_one_week_reminder(user) do @@ -90,7 +90,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("trial-one-week-reminder") |> subject("Your Plausible trial expires next week") - |> render("trial_one_week_reminder.html", user: user) + |> render(:trial_one_week_reminder, user: user) end def trial_upgrade_email(user, day, usage) do @@ -100,7 +100,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("trial-upgrade-email") |> subject("Your Plausible trial ends #{day}") - |> render("trial_upgrade_email.html", + |> render(:trial_upgrade_email, user: user, day: day, custom_events: usage.custom_events, @@ -114,7 +114,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("trial-over-email") |> subject("Your Plausible trial has ended") - |> render("trial_over_email.html", + |> render(:trial_over_email, user: user, extra_offset: Plausible.Auth.User.trial_accept_traffic_until_offset_days() ) @@ -133,7 +133,7 @@ defmodule PlausibleWeb.Email do |> to(email) |> tag("spike-notification") |> subject("Traffic Spike on #{site.domain}") - |> render("spike_notification.html", %{ + |> render(:spike_notification, %{ site: site, current_visitors: current_visitors, sources: sources, @@ -146,7 +146,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("over-limit") |> subject("[Action required] You have outgrown your Plausible subscription tier") - |> render("over_limit.html", %{ + |> render(:over_limit, %{ user: user, usage: usage, suggested_plan: suggested_plan @@ -158,7 +158,7 @@ defmodule PlausibleWeb.Email do |> to("enterprise@plausible.io") |> tag("enterprise-over-limit") |> subject("#{user.email} has outgrown their enterprise plan") - |> render("enterprise_over_limit_internal.html", %{ + |> render(:enterprise_over_limit_internal, %{ user: user, pageview_usage: pageview_usage, site_usage: site_usage, @@ -171,7 +171,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("dashboard-locked") |> subject("[Action required] Your Plausible dashboard is now locked") - |> render("dashboard_locked.html", %{ + |> render(:dashboard_locked, %{ user: user, usage: usage, suggested_plan: suggested_plan @@ -185,7 +185,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("yearly-renewal") |> subject("Your Plausible subscription is up for renewal") - |> render("yearly_renewal_notification.html", %{ + |> render(:yearly_renewal_notification, %{ user: user, date: date, next_bill_amount: user.subscription.next_bill_amount, @@ -205,7 +205,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("yearly-expiration") |> subject("Your Plausible subscription is about to expire") - |> render("yearly_expiration_notification.html", %{ + |> render(:yearly_expiration_notification, %{ user: user, next_bill_date: next_bill_date, accept_traffic_until: accept_traffic_until @@ -217,7 +217,7 @@ defmodule PlausibleWeb.Email do |> to(user.email) |> tag("cancelled-email") |> subject("Mind sharing your thoughts on Plausible?") - |> render("cancellation_email.html", user: user) + |> render(:cancellation_email, user: user) end def new_user_invitation(invitation) do @@ -225,7 +225,7 @@ defmodule PlausibleWeb.Email do |> to(invitation.email) |> tag("new-user-invitation") |> subject("[#{Plausible.product_name()}] You've been invited to #{invitation.site.domain}") - |> render("new_user_invitation.html", + |> render(:new_user_invitation, invitation: invitation ) end @@ -235,7 +235,7 @@ defmodule PlausibleWeb.Email do |> to(invitation.email) |> tag("existing-user-invitation") |> subject("[#{Plausible.product_name()}] You've been invited to #{invitation.site.domain}") - |> render("existing_user_invitation.html", + |> render(:existing_user_invitation, invitation: invitation ) end @@ -247,7 +247,7 @@ defmodule PlausibleWeb.Email do |> subject( "[#{Plausible.product_name()}] Request to transfer ownership of #{invitation.site.domain}" ) - |> render("ownership_transfer_request.html", + |> render(:ownership_transfer_request, invitation: invitation, new_owner_account: new_owner_account ) @@ -260,7 +260,7 @@ defmodule PlausibleWeb.Email do |> subject( "[#{Plausible.product_name()}] #{invitation.email} accepted your invitation to #{invitation.site.domain}" ) - |> render("invitation_accepted.html", + |> render(:invitation_accepted, user: invitation.inviter, invitation: invitation ) @@ -273,7 +273,7 @@ defmodule PlausibleWeb.Email do |> subject( "[#{Plausible.product_name()}] #{invitation.email} rejected your invitation to #{invitation.site.domain}" ) - |> render("invitation_rejected.html", + |> render(:invitation_rejected, user: invitation.inviter, invitation: invitation ) @@ -286,7 +286,7 @@ defmodule PlausibleWeb.Email do |> subject( "[#{Plausible.product_name()}] #{invitation.email} accepted the ownership transfer of #{invitation.site.domain}" ) - |> render("ownership_transfer_accepted.html", + |> render(:ownership_transfer_accepted, user: invitation.inviter, invitation: invitation ) @@ -299,7 +299,7 @@ defmodule PlausibleWeb.Email do |> subject( "[#{Plausible.product_name()}] #{invitation.email} rejected the ownership transfer of #{invitation.site.domain}" ) - |> render("ownership_transfer_rejected.html", + |> render(:ownership_transfer_rejected, user: invitation.inviter, invitation: invitation ) @@ -312,7 +312,7 @@ defmodule PlausibleWeb.Email do |> subject( "[#{Plausible.product_name()}] Your access to #{membership.site.domain} has been revoked" ) - |> render("site_member_removed.html", + |> render(:site_member_removed, user: membership.user, membership: membership ) @@ -371,7 +371,7 @@ defmodule PlausibleWeb.Email do |> to(user) |> tag("export-success") |> subject("[#{Plausible.product_name()}] Your export is now ready for download") - |> render("export_success.html", + |> render(:export_success, user: user, site: site, download_url: download_url, @@ -383,7 +383,7 @@ defmodule PlausibleWeb.Email do priority_email() |> to(user) |> subject("[#{Plausible.product_name()}] Your export has failed") - |> render("export_failure.html", user: user, site: site) + |> render(:export_failure, user: user, site: site) end def error_report(reported_by, trace_id, feedback) do @@ -394,7 +394,7 @@ defmodule PlausibleWeb.Email do |> put_param("ReplyTo", reported_by) |> tag("sentry") |> subject("Feedback to Sentry Trace #{trace_id}") - |> render("error_report_email.html", %{ + |> render(:error_report_email, %{ reported_by: reported_by, feedback: feedback, trace_id: trace_id @@ -406,7 +406,7 @@ defmodule PlausibleWeb.Email do |> to(notification.email) |> tag("drop-traffic-warning-first") |> subject("We'll stop counting your stats") - |> render("approaching_accept_traffic_until.html", + |> render(:approaching_accept_traffic_until, time: "next week", user: %{email: notification.email, name: notification.name} ) @@ -417,7 +417,7 @@ defmodule PlausibleWeb.Email do |> to(notification.email) |> tag("drop-traffic-warning-final") |> subject("A reminder that we'll stop counting your stats tomorrow") - |> render("approaching_accept_traffic_until.html", + |> render(:approaching_accept_traffic_until, time: "tomorrow", user: %{email: notification.email, name: notification.name} ) @@ -427,14 +427,14 @@ defmodule PlausibleWeb.Email do Unlike the default 'base' emails, priority emails cannot be unsubscribed from. This is achieved by sending them through a dedicated 'priority' message stream in Postmark. """ - def priority_email(), do: priority_email(%{layout: "priority_email.html"}) + def priority_email(), do: priority_email(%{layout: :priority_email}) def priority_email(%{layout: layout}) do base_email(%{layout: layout}) |> put_param("MessageStream", "priority") end - def base_email(), do: base_email(%{layout: "base_email.html"}) + def base_email(), do: base_email(%{layout: :base_email}) def base_email(%{layout: layout}) do mailer_from = Application.get_env(:plausible, :mailer_email) @@ -447,7 +447,7 @@ defmodule PlausibleWeb.Email do defp maybe_put_layout(email, nil), do: email - defp maybe_put_layout(email, layout) do - put_html_layout(email, {PlausibleWeb.LayoutView, layout}) + defp maybe_put_layout(email, layout) when is_atom(layout) do + put_layout(email, {PlausibleWeb.LayoutView, layout}) end end diff --git a/lib/plausible_web/templates/email/activation_email.text.eex b/lib/plausible_web/templates/email/activation_email.text.eex new file mode 100644 index 000000000000..6373e81b85a0 --- /dev/null +++ b/lib/plausible_web/templates/email/activation_email.text.eex @@ -0,0 +1 @@ +Enter <%= @code %> to verify your email address. This code will expire in 4 hours. diff --git a/lib/plausible_web/templates/email/approaching_accept_traffic_until.text.eex b/lib/plausible_web/templates/email/approaching_accept_traffic_until.text.eex new file mode 100644 index 000000000000..8fc2021ad152 --- /dev/null +++ b/lib/plausible_web/templates/email/approaching_accept_traffic_until.text.eex @@ -0,0 +1,7 @@ +You used to have an active account with <%= Plausible.product_name() %>, a simple, lightweight, open source and privacy-first Google Analytics alternative. + +We've noticed that you're still sending us stats so we're writing to inform you that we'll stop accepting stats from your sites <%= @time %>. We're an independent, bootstrapped service and we don't sell your data, so this will reduce our server costs and help keep us sustainable. + +If you'd like to continue counting your site stats in a privacy-friendly way, please login to your Plausible account at <%= plausible_url() %> and start a subscription. + +Do you have any questions or need help with anything? Just reply to this email and we'll gladly help. diff --git a/lib/plausible_web/templates/email/cancellation_email.text.eex b/lib/plausible_web/templates/email/cancellation_email.text.eex new file mode 100644 index 000000000000..068e455ab5ce --- /dev/null +++ b/lib/plausible_web/templates/email/cancellation_email.text.eex @@ -0,0 +1 @@ +This is Marko, one of the co-founders of Plausible. I'd love to understand the reasons behind your decision to cancel your subscription. We're solely funded by our subscribers so we genuinely value your feedback. Even a few words would be beneficial in helping us improve our product. Please respond to this email with any insights you can share. Thank you for your time! diff --git a/lib/plausible_web/templates/email/check_stats_email.text.eex b/lib/plausible_web/templates/email/check_stats_email.text.eex new file mode 100644 index 000000000000..7f22a6cc6b3b --- /dev/null +++ b/lib/plausible_web/templates/email/check_stats_email.text.eex @@ -0,0 +1,14 @@ +Plausible is tracking your website stats without compromising the user experience and the privacy of your visitors. + +Here's how to get even more out of your Plausible experience: + +* Set up custom events: https://plausible.io/docs/custom-event-goals and pageview goals: https://plausible.io/docs/pageview-goals to count actions you want your visitors to take +* Running an ecommerce? Assign monetary values to custom events to track revenue attribution: https://plausible.io/docs/ecommerce-revenue-tracking +* Follow the journey from a landing page to conversion with funnel analysis: https://plausible.io/docs/funnel-analysis +* Tag your social media, email and paid links: https://plausible.io/docs/manual-link-tagging to see which campaigns are responsible for most conversions +* Send custom properties: https://plausible.io/docs/custom-props/introduction to collect data that we don't track automatically +* Explore our stats API: https://plausible.io/docs/stats-api to retrieve your stats and our sites API: https://plausible.io/docs/sites-api to create and manage sites programmatically + +View your Plausible dashboard now: <%= plausible_url() %> for the most valuable traffic insights at a glance. + +Do reply back to this email if you have any questions or need some guidance. diff --git a/lib/plausible_web/templates/email/create_site_email.text.eex b/lib/plausible_web/templates/email/create_site_email.text.eex new file mode 100644 index 000000000000..9deebf3f8b4c --- /dev/null +++ b/lib/plausible_web/templates/email/create_site_email.text.eex @@ -0,0 +1,5 @@ +You've activated your free 30-day trial of Plausible, a simple and privacy-friendly website analytics tool. + +Click here: <%= "#{plausible_url()}/sites/new" %> to add your website URL, your timezone and install our one-line JavaScript snippet to start collecting visitor statistics. + +Do reply back to this email if you have any questions or need some guidance. diff --git a/lib/plausible_web/templates/email/csv_import.text.eex b/lib/plausible_web/templates/email/csv_import.text.eex new file mode 100644 index 000000000000..4e2fda194d20 --- /dev/null +++ b/lib/plausible_web/templates/email/csv_import.text.eex @@ -0,0 +1,10 @@ +<%= if @success do %> +Your CSV import has completed successfully. The Plausible dashboard for <%= @site_import.site.domain %> now contains historical +imported data from <%= date_format(@site_import.start_date) %> to <%= date_format(@site_import.end_date) %> + +Visit <%= @link %> to view your dashboard. +<% else %> +Unfortunately, your CSV import for <%= @site_import.site.domain %> did not complete successfully. Sorry about that! + +Please try to do the import once again.<%= if ee?() do %> Please reply to this email to let us know if you're still experiencing issues with the import.<% end %> +<% end %> diff --git a/lib/plausible_web/templates/email/dashboard_locked.text.eex b/lib/plausible_web/templates/email/dashboard_locked.text.eex new file mode 100644 index 000000000000..8f294267c80e --- /dev/null +++ b/lib/plausible_web/templates/email/dashboard_locked.text.eex @@ -0,0 +1,15 @@ +Last week we sent a reminder that your site traffic has exceeded the limits of your <%= Plausible.product_name() %> subscription tier for two consecutive months. Since we haven't received a response, we've had to temporarily lock access to your stats. + +Your subscription is still active, we're still counting your stats and haven't deleted any of your data but as you have outgrown your subscription tier, we kindly ask you to upgrade to match your new traffic levels. Upon upgrading to a suitable tier, your dashboard access will be immediately restored. + +During the last billing cycle (<%= PlausibleWeb.TextHelpers.format_date_range(@usage.last_cycle.date_range) %>), your account recorded <%= PlausibleWeb.AuthView.delimit_integer(@usage.last_cycle.total) %> billable pageviews. In the billing cycle before that (<%= PlausibleWeb.TextHelpers.format_date_range(@usage.penultimate_cycle.date_range) %>), the usage was <%= PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total) %> billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your account settings (<%= plausible_url() <> PlausibleWeb.Router.Helpers.auth_path(PlausibleWeb.Endpoint, :user_settings) %>), you'll find an overview of your usage and limits. + +<%= if @suggested_plan == :enterprise do %> +Your usage exceeds our standard plans, so please reply back to this email for a tailored quote. +<% else %> +Click here to upgrade your subscription: <%= PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) %>. We recommend you upgrade to the <%= @suggested_plan.volume %>/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire. +<% end %> + +Do you have questions or need help with anything? Just reply to this email. We're here to help! + +Thanks for understanding and for being a Plausible subscriber! diff --git a/lib/plausible_web/templates/email/enterprise_over_limit_internal.text.eex b/lib/plausible_web/templates/email/enterprise_over_limit_internal.text.eex new file mode 100644 index 000000000000..522c4e50dd1f --- /dev/null +++ b/lib/plausible_web/templates/email/enterprise_over_limit_internal.text.eex @@ -0,0 +1,8 @@ +Automated notice about an enterprise account that has gone over their limits. + +Customer email: <%= @user.email %> +Last billing cycle: <%= PlausibleWeb.TextHelpers.format_date_range(@pageview_usage.last_cycle.date_range) %> +Last cycle pageview usage: <%= PlausibleWeb.AuthView.delimit_integer(@pageview_usage.last_cycle.total) %> billable pageviews +Penultimate billing cycle: <%= PlausibleWeb.TextHelpers.format_date_range(@pageview_usage.penultimate_cycle.date_range) %> +Penultimate cycle pageview usage: <%= PlausibleWeb.AuthView.delimit_integer(@pageview_usage.penultimate_cycle.total) %> billable pageviews +Site usage: <%= @site_usage %> / <%= @site_allowance %> allowed sites diff --git a/lib/plausible_web/templates/email/error_report_email.text.eex b/lib/plausible_web/templates/email/error_report_email.text.eex new file mode 100644 index 000000000000..10a5d21a0d93 --- /dev/null +++ b/lib/plausible_web/templates/email/error_report_email.text.eex @@ -0,0 +1,7 @@ +Error report + +Reported by: <%= @reported_by %> +Sentry trace: <%= sentry_link(@trace_id) %> (<%= @trace_id %>) + +User feedback: +<%= @feedback %> diff --git a/lib/plausible_web/templates/email/existing_user_invitation.html.eex b/lib/plausible_web/templates/email/existing_user_invitation.html.eex index 32554a2320b9..d2efc990586d 100644 --- a/lib/plausible_web/templates/email/existing_user_invitation.html.eex +++ b/lib/plausible_web/templates/email/existing_user_invitation.html.eex @@ -1,3 +1,3 @@ <%= @invitation.inviter.email %> has invited you to the <%= @invitation.site.domain %> site on <%= Plausible.product_name() %>. -<%= link("Click here", to: Routes.site_url(PlausibleWeb.Endpoint, :index)) %> to view and respond to the invitation. The invitation +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :index) %> to view and respond to the invitation. The invitation will expire 48 hours after this email is sent. diff --git a/lib/plausible_web/templates/email/existing_user_invitation.text.eex b/lib/plausible_web/templates/email/existing_user_invitation.text.eex new file mode 100644 index 000000000000..cf3bc36fe000 --- /dev/null +++ b/lib/plausible_web/templates/email/existing_user_invitation.text.eex @@ -0,0 +1,3 @@ +<%= @invitation.inviter.email %> has invited you to the <%= @invitation.site.domain %> site on <%= Plausible.product_name() %>. + +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :index) %> to view and respond to the invitation. The invitation will expire 48 hours after this email is sent. diff --git a/lib/plausible_web/templates/email/export_failure.text.eex b/lib/plausible_web/templates/email/export_failure.text.eex new file mode 100644 index 000000000000..762a48f2add7 --- /dev/null +++ b/lib/plausible_web/templates/email/export_failure.text.eex @@ -0,0 +1,8 @@ +Your <%= Plausible.product_name() %> export for <%= @site.domain %> has encountered an error and was unsuccessful. + +Sorry for the trouble this may have caused. + +Please attempt to export your data again. +<%= if ee?() do %> +Should the problem persist, do reply to this email so we can assist. Thanks! +<% end %> diff --git a/lib/plausible_web/templates/email/export_success.text.eex b/lib/plausible_web/templates/email/export_success.text.eex new file mode 100644 index 000000000000..1566b69eadd4 --- /dev/null +++ b/lib/plausible_web/templates/email/export_success.text.eex @@ -0,0 +1,5 @@ +Your <%= Plausible.product_name() %> export for <%= @site.domain %> is now ready for download. + +Please visit <%= @download_url %> to start the download process. +<%= if @expires_in do %> +Note that this link will expire <%= @expires_in %>.<% end %> diff --git a/lib/plausible_web/templates/email/google_analytics_import.text.eex b/lib/plausible_web/templates/email/google_analytics_import.text.eex new file mode 100644 index 000000000000..7d21e1d9b0ff --- /dev/null +++ b/lib/plausible_web/templates/email/google_analytics_import.text.eex @@ -0,0 +1,12 @@ +<%= if @success do %> +Your Google Analytics import has completed successfully. The Plausible dashboard for <%= @site_import.site.domain %> now contains historical imported data from <%= date_format(@site_import.start_date) %> to <%= date_format(@site_import.end_date) %> + +Visit <%= @link %> to view your dashboard. +<% else %> +Unfortunately, your Google Analytics import for <%= @site_import.site.domain %> did not complete successfully. Sorry about that! + +Please try to do the import once again. Sometimes the Google Analytics API just randomly returns empty data. It's intermittent and random. Trying to do the import again may return what you need. +<%= if ee?() do %> +Please reply to this email to let us know if you're still experiencing issues with the import. +<% end %> +<% end %> diff --git a/lib/plausible_web/templates/email/invitation_accepted.text.eex b/lib/plausible_web/templates/email/invitation_accepted.text.eex new file mode 100644 index 000000000000..a6849eeaa652 --- /dev/null +++ b/lib/plausible_web/templates/email/invitation_accepted.text.eex @@ -0,0 +1,3 @@ +<%= @invitation.email %> has accepted your invitation to <%= @invitation.site.domain %>. + +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @invitation.site.domain) %> to view site settings. diff --git a/lib/plausible_web/templates/email/invitation_rejected.text.eex b/lib/plausible_web/templates/email/invitation_rejected.text.eex new file mode 100644 index 000000000000..f4201950bbfb --- /dev/null +++ b/lib/plausible_web/templates/email/invitation_rejected.text.eex @@ -0,0 +1,3 @@ +<%= @invitation.email %> has rejected your invitation to <%= @invitation.site.domain %>. + +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @invitation.site.domain) %> to view site settings. diff --git a/lib/plausible_web/templates/email/new_user_invitation.text.eex b/lib/plausible_web/templates/email/new_user_invitation.text.eex new file mode 100644 index 000000000000..a65c2177e975 --- /dev/null +++ b/lib/plausible_web/templates/email/new_user_invitation.text.eex @@ -0,0 +1,5 @@ +<%= @invitation.inviter.email %> has invited you to join the <%= @invitation.site.domain %> site on <%= Plausible.product_name() %>. + +Visit <%= Routes.auth_url(PlausibleWeb.Endpoint, :register_from_invitation_form, @invitation.invitation_id) %> to create your account. The link is valid for 48 hours after this email is sent. + +Plausible is a lightweight and open-source website analytics tool. We hope you like our simple and ethical approach to tracking website visitors. diff --git a/lib/plausible_web/templates/email/over_limit.text.eex b/lib/plausible_web/templates/email/over_limit.text.eex new file mode 100644 index 000000000000..46901ad4ccbe --- /dev/null +++ b/lib/plausible_web/templates/email/over_limit.text.eex @@ -0,0 +1,17 @@ +Thanks for being a <%= Plausible.product_name() %> subscriber! + +This is a friendly reminder that your traffic has exceeded your subscription tier for two consecutive months. Congrats on all that traffic! + +To maintain uninterrupted access to your stats, we kindly ask you to upgrade your account to match your new traffic levels. Please note, if your account isn't upgraded within the next 7 days, access to your stats will be temporarily locked. + +During the last billing cycle (<%= PlausibleWeb.TextHelpers.format_date_range(@usage.last_cycle.date_range) %>), your account recorded <%= PlausibleWeb.AuthView.delimit_integer(@usage.last_cycle.total) %> billable pageviews. In the billing cycle before that (<%= PlausibleWeb.TextHelpers.format_date_range(@usage.penultimate_cycle.date_range) %>), your account used <%= PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total) %> billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your account settings (<%= plausible_url() <> PlausibleWeb.Router.Helpers.auth_path(PlausibleWeb.Endpoint, :user_settings) %>), you'll find an overview of your usage and limits. + +<%= if @suggested_plan == :enterprise do %> +Your usage exceeds our standard plans, so please reply back to this email for a tailored quote. +<% else %> +Please visit <%= PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) %> to upgrade your subscription. We recommend you upgrade to the <%= @suggested_plan.volume %>/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire. +<% end %> + +Do you have questions or need help with anything? Just reply to this email. We're here to help! + +Thanks again for using our product and for your support! diff --git a/lib/plausible_web/templates/email/ownership_transfer_accepted.text.eex b/lib/plausible_web/templates/email/ownership_transfer_accepted.text.eex new file mode 100644 index 000000000000..183480feeeaf --- /dev/null +++ b/lib/plausible_web/templates/email/ownership_transfer_accepted.text.eex @@ -0,0 +1,3 @@ +<%= @invitation.email %> has accepted the ownership transfer of <%= @invitation.site.domain %>. They will be responsible for billing of it going forward and your role has been changed to admin. + +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @invitation.site.domain) %> to view site settings. diff --git a/lib/plausible_web/templates/email/ownership_transfer_rejected.text.eex b/lib/plausible_web/templates/email/ownership_transfer_rejected.text.eex new file mode 100644 index 000000000000..4db5c8a20040 --- /dev/null +++ b/lib/plausible_web/templates/email/ownership_transfer_rejected.text.eex @@ -0,0 +1,3 @@ +<%= @invitation.email %> has rejected the ownership transfer of <%= @invitation.site.domain %>. + +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @invitation.site.domain) %> to view site settings. diff --git a/lib/plausible_web/templates/email/ownership_transfer_request.text.eex b/lib/plausible_web/templates/email/ownership_transfer_request.text.eex new file mode 100644 index 000000000000..1160cf7dfdda --- /dev/null +++ b/lib/plausible_web/templates/email/ownership_transfer_request.text.eex @@ -0,0 +1,9 @@ +<%= @invitation.inviter.email %> has requested to transfer the ownership of <%= @invitation.site.domain %> site on <%= Plausible.product_name() %> to you. + +<%= if @new_owner_account do %> +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :index) %> to view and respond to the invitation. +<% else %> +Visit <%= Routes.auth_url(PlausibleWeb.Endpoint, :register_form, invitation: @invitation.invitation_id) %> to create your account. + +Plausible is a lightweight and open-source website analytics tool. We hope you like our simple and ethical approach to tracking website visitors. +<% end %> diff --git a/lib/plausible_web/templates/email/password_reset_email.text.eex b/lib/plausible_web/templates/email/password_reset_email.text.eex new file mode 100644 index 000000000000..783bbe96c080 --- /dev/null +++ b/lib/plausible_web/templates/email/password_reset_email.text.eex @@ -0,0 +1,3 @@ +Visit <%= @reset_link %> to reset your Plausible password. + +This link will expire in 1 hour. If you don't use it by then, you can request another login link. diff --git a/lib/plausible_web/templates/email/site_member_removed.text.eex b/lib/plausible_web/templates/email/site_member_removed.text.eex new file mode 100644 index 000000000000..7ae8263b2a60 --- /dev/null +++ b/lib/plausible_web/templates/email/site_member_removed.text.eex @@ -0,0 +1,3 @@ +An administrator of <%= @membership.site.domain %> has removed you as a member. You won't be able to see the stats anymore. + +Visit <%= Routes.site_url(PlausibleWeb.Endpoint, :index) %> to view your sites. diff --git a/lib/plausible_web/templates/email/site_setup_help_email.text.eex b/lib/plausible_web/templates/email/site_setup_help_email.text.eex new file mode 100644 index 000000000000..5e22e26578bd --- /dev/null +++ b/lib/plausible_web/templates/email/site_setup_help_email.text.eex @@ -0,0 +1,11 @@ +<%= if Plausible.Users.on_trial?(@user) do %> +You signed up for a free 30-day trial of Plausible, a simple and privacy-friendly website analytics tool. +<% end %> + +To finish your setup for <%= @site.domain %>, you need to install this lightweight line of JavaScript code: <%= "#{plausible_url()}/#{URI.encode_www_form(@site.domain)}/snippet" %> into your site to start collecting visitor statistics. + +This Plausible script is 45 times smaller than Google Analytics script so you'll have a fast loading site while getting all the important traffic insights on one single page. + +On WordPress? We have a WordPress plugin: https://plausible.io/wordpress-analytics-plugin that makes the process simpler. We also have integration guides: https://plausible.io/docs/integration-guides for different site builders to help you start counting stats in no time. + +Do reply back to this email if you have any questions or need some guidance. diff --git a/lib/plausible_web/templates/email/site_setup_success_email.text.eex b/lib/plausible_web/templates/email/site_setup_success_email.text.eex new file mode 100644 index 000000000000..91379ea04f89 --- /dev/null +++ b/lib/plausible_web/templates/email/site_setup_success_email.text.eex @@ -0,0 +1,13 @@ +Congrats! We've recorded the first visitor on <%= @site.domain %>. Your traffic is now being counted without compromising the user experience and privacy of your visitors. + +Do check out your easy to use, fast-loading and privacy-friendly dashboard: <%= "#{plausible_url()}/#{URI.encode_www_form(@site.domain)}" %>. + +Something looks off? Take a look at our installation troubleshooting guide: https://plausible.io/docs/troubleshoot-integration. + +<%= if Plausible.Users.on_trial?(@user) do %> +You're on a 30-day free trial with no obligations so do take your time to explore Plausible. Here's how to get the most out of your Plausible experience: https://plausible.io/docs/your-plausible-experience. +<% end %> + +PS: You can import your historical Google Analytics stats into your Plausible dashboard. Learn how our GA importer works: https://plausible.io/docs/google-analytics-import. + +Do reply back to this email if you have any questions. We're here to help. diff --git a/lib/plausible_web/templates/email/spike_notification.text.eex b/lib/plausible_web/templates/email/spike_notification.text.eex new file mode 100644 index 000000000000..e82011208c14 --- /dev/null +++ b/lib/plausible_web/templates/email/spike_notification.text.eex @@ -0,0 +1,14 @@ +There are currently <%= @current_visitors %> visitors on <%= @site.domain %>. + +<%= unless Enum.empty?(@sources) do %> +The top sources for current visitors: +<%= for %{name: source, count: visitors} <- @sources do %> + <%= source %> - <%= visitors %> visitor<%= if visitors > 1, do: "s" %> +<% end %> +<% end %> + +<%= if @link do %> +View dashboard: <%= @link %> +<% end %> + +Congrats on the spike in traffic! diff --git a/lib/plausible_web/templates/email/trial_one_week_reminder.text.eex b/lib/plausible_web/templates/email/trial_one_week_reminder.text.eex new file mode 100644 index 000000000000..f3bb00996b24 --- /dev/null +++ b/lib/plausible_web/templates/email/trial_one_week_reminder.text.eex @@ -0,0 +1,7 @@ +Time flies! Your 30-day free trial of Plausible will end next week. + +Over the last three weeks, we hope you got to experience the potential benefits of having website stats in an easy to use dashboard while respecting the privacy of your visitors, not annoying them with the cookie and privacy notices, and still having a fast loading site. + +In order to continue receiving valuable website traffic insights at a glance, you'll need to upgrade your account: <%= PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) %>. + +If you have any questions or feedback for us, feel free to reply to this email. diff --git a/lib/plausible_web/templates/email/trial_over_email.text.eex b/lib/plausible_web/templates/email/trial_over_email.text.eex new file mode 100644 index 000000000000..e8403dc0382f --- /dev/null +++ b/lib/plausible_web/templates/email/trial_over_email.text.eex @@ -0,0 +1,5 @@ +Your free Plausible trial has now expired. Upgrade your account to continue receiving valuable website traffic insights at a glance while respecting the privacy of your visitors and still having a fast loading site. + +Upgrade now: <%= PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) %> + +We will keep recording stats for <%= @extra_offset %> days to give you time to upgrade. diff --git a/lib/plausible_web/templates/email/trial_upgrade_email.text.eex b/lib/plausible_web/templates/email/trial_upgrade_email.text.eex new file mode 100644 index 000000000000..12196c638032 --- /dev/null +++ b/lib/plausible_web/templates/email/trial_upgrade_email.text.eex @@ -0,0 +1,13 @@ +Thanks for exploring Plausible, a simple and privacy-friendly alternative to Google Analytics. Your free 30-day trial is ending <%= @day %>, but you can keep using Plausible by upgrading to a paid plan. + +In the last month, your account has used <%= PlausibleWeb.AuthView.delimit_integer(@usage) %> billable pageviews<%= if @custom_events > 0, do: " and custom events in total", else: "" %>. + +<%= if @suggested_plan == :enterprise do %> +This is more than our standard plans, so please reply back to this email to get a quote for your volume. +<% else %> +Based on that we recommend you select a <%= @suggested_plan.volume %>/mo plan. + +Upgrade now: <%= PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) %> + +Have a question, feedback or need some guidance? Just reply to this email to get in touch! +<% end %> diff --git a/lib/plausible_web/templates/email/two_factor_disabled_email.text.eex b/lib/plausible_web/templates/email/two_factor_disabled_email.text.eex new file mode 100644 index 000000000000..8f09d9717f3b --- /dev/null +++ b/lib/plausible_web/templates/email/two_factor_disabled_email.text.eex @@ -0,0 +1 @@ +Two-Factor Authentication is now disabled on your account. diff --git a/lib/plausible_web/templates/email/two_factor_enabled_email.text.eex b/lib/plausible_web/templates/email/two_factor_enabled_email.text.eex new file mode 100644 index 000000000000..62351bce8b75 --- /dev/null +++ b/lib/plausible_web/templates/email/two_factor_enabled_email.text.eex @@ -0,0 +1 @@ +Two-Factor Authentication is now enabled on your account. diff --git a/lib/plausible_web/templates/email/welcome_email.text.eex b/lib/plausible_web/templates/email/welcome_email.text.eex new file mode 100644 index 000000000000..8272efe6dd1b --- /dev/null +++ b/lib/plausible_web/templates/email/welcome_email.text.eex @@ -0,0 +1,14 @@ +We are building Plausible to provide a simple and ethical approach to tracking website visitors. We're super excited to have you on board! + +Here's how to get the most out of your Plausible experience: + +* Enable email reports: https://plausible.io/docs/email-reports and notifications for traffic spikes: https://plausible.io/docs/traffic-spikes +* Integrate with Search Console: https://plausible.io/docs/google-search-console-integration to get keyword phrases people find your site with +* Invite team members and other collaborators: https://plausible.io/docs/users-roles +* Set up easy goals including 404 error pages: https://plausible.io/docs/error-pages-tracking-404, file downloads: https://plausible.io/docs/file-downloads-tracking, and outbound link clicks: https://plausible.io/docs/outbound-link-click-tracking +* Opt out from counting your own visits: https://plausible.io/docs/excluding +* If you're concerned about adblockers, set up a proxy to bypass them: https://plausible.io/docs/proxy/introduction + +Then you're ready to start exploring your fast loading, ethical, and actionable Plausible dashboard: https://plausible.io/sites. + +Have a question, feedback, or need some guidance? Do reply back to this email. diff --git a/lib/plausible_web/templates/email/yearly_expiration_notification.text.eex b/lib/plausible_web/templates/email/yearly_expiration_notification.text.eex new file mode 100644 index 000000000000..5fc7458fd2e0 --- /dev/null +++ b/lib/plausible_web/templates/email/yearly_expiration_notification.text.eex @@ -0,0 +1,7 @@ +Time flies! This is a reminder that your annual subscription for <%= Plausible.product_name() %> will expire on <%= @next_bill_date %>. + +You need to renew your subscription: <%= PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan) %> if you want to continue using Plausible to count your website stats in a privacy-friendly way. + +If you don't want to continue your subscription, there's no action required. You will lose access to your dashboard on <%= @next_bill_date %> and we'll stop accepting stats on <%= @accept_traffic_until %>. + +Have a question, feedback or need some guidance? Just reply to this email to get in touch! diff --git a/lib/plausible_web/templates/email/yearly_renewal_notification.text.eex b/lib/plausible_web/templates/email/yearly_renewal_notification.text.eex new file mode 100644 index 000000000000..45212d87cae9 --- /dev/null +++ b/lib/plausible_web/templates/email/yearly_renewal_notification.text.eex @@ -0,0 +1,9 @@ +Time flies! This is a reminder that your annual subscription for <%= Plausible.product_name() %> is due to renew on <%= @date %>. We will automatically charge <%= PlausibleWeb.BillingView.present_currency(@currency) %><%= @next_bill_amount %> from your preferred billing method. + +There's no action required if you're happy to continue using Plausible to count your website stats in a privacy-friendly way. + +If you don't want to continue your subscription, you can cancel it on your account settings page: <%= "#{plausible_url()}/settings" %>. + +BTW, most of our subscribers come from word of mouth, so if you love Plausible, and know someone else who might find it useful, we'd appreciate if you'd let them know. Thank you! + +Have a question, feedback or need some guidance? Do reply back to this email. diff --git a/lib/plausible_web/templates/layout/base_email.text.eex b/lib/plausible_web/templates/layout/base_email.text.eex new file mode 100644 index 000000000000..0de9dd4c22d8 --- /dev/null +++ b/lib/plausible_web/templates/layout/base_email.text.eex @@ -0,0 +1,10 @@ +<%= PlausibleWeb.EmailView.greet_recipient(assigns) %> + +<%= @inner_content %> + +<%= if ee?() do %>Regards, +The Plausible Team 💌<% end %> + +-- + +<%= plausible_url() %> diff --git a/lib/plausible_web/templates/layout/priority_email.text.eex b/lib/plausible_web/templates/layout/priority_email.text.eex new file mode 100644 index 000000000000..0de9dd4c22d8 --- /dev/null +++ b/lib/plausible_web/templates/layout/priority_email.text.eex @@ -0,0 +1,10 @@ +<%= PlausibleWeb.EmailView.greet_recipient(assigns) %> + +<%= @inner_content %> + +<%= if ee?() do %>Regards, +The Plausible Team 💌<% end %> + +-- + +<%= plausible_url() %> diff --git a/test/plausible_web/email_test.exs b/test/plausible_web/email_test.exs index 984f7f2685f1..9a7ef2b15618 100644 --- a/test/plausible_web/email_test.exs +++ b/test/plausible_web/email_test.exs @@ -7,7 +7,7 @@ defmodule PlausibleWeb.EmailTest do test "greets user by first name if user in template assigns" do email = Email.base_email() - |> Email.render("welcome_email.html", %{ + |> Email.render(:welcome_email, %{ user: build(:user, name: "John Doe"), code: "123" }) @@ -18,7 +18,7 @@ defmodule PlausibleWeb.EmailTest do test "greets impersonally when user not in template assigns" do email = Email.base_email() - |> Email.render("welcome_email.html") + |> Email.render(:welcome_email) assert email.html_body =~ "Hey," end @@ -26,7 +26,7 @@ defmodule PlausibleWeb.EmailTest do test "renders plausible link" do email = Email.base_email() - |> Email.render("welcome_email.html") + |> Email.render(:welcome_email) assert email.html_body =~ plausible_link() end @@ -35,7 +35,7 @@ defmodule PlausibleWeb.EmailTest do test "renders unsubscribe placeholder" do email = Email.base_email() - |> Email.render("welcome_email.html") + |> Email.render(:welcome_email) assert email.html_body =~ "{{{ pm:unsubscribe }}}" end @@ -43,7 +43,7 @@ defmodule PlausibleWeb.EmailTest do test "can be disabled with a nil layout" do email = Email.base_email(%{layout: nil}) - |> Email.render("welcome_email.html", %{ + |> Email.render(:welcome_email, %{ user: build(:user, name: "John Doe") }) @@ -56,7 +56,7 @@ defmodule PlausibleWeb.EmailTest do test "uses the `priority` message stream in Postmark" do email = Email.priority_email() - |> Email.render("activation_email.html", %{ + |> Email.render(:activation_email, %{ user: build(:user, name: "John Doe"), code: "123" }) @@ -67,7 +67,7 @@ defmodule PlausibleWeb.EmailTest do test "greets user by first name if user in template assigns" do email = Email.priority_email() - |> Email.render("activation_email.html", %{ + |> Email.render(:activation_email, %{ user: build(:user, name: "John Doe"), code: "123" }) @@ -78,7 +78,7 @@ defmodule PlausibleWeb.EmailTest do test "greets impersonally when user not in template assigns" do email = Email.priority_email() - |> Email.render("password_reset_email.html", %{ + |> Email.render(:password_reset_email, %{ reset_link: "imaginary" }) @@ -88,7 +88,7 @@ defmodule PlausibleWeb.EmailTest do test "renders plausible link" do email = Email.priority_email() - |> Email.render("password_reset_email.html", %{ + |> Email.render(:password_reset_email, %{ reset_link: "imaginary" }) @@ -98,7 +98,7 @@ defmodule PlausibleWeb.EmailTest do test "does not render unsubscribe placeholder" do email = Email.priority_email() - |> Email.render("password_reset_email.html", %{ + |> Email.render(:password_reset_email, %{ reset_link: "imaginary" }) @@ -108,7 +108,7 @@ defmodule PlausibleWeb.EmailTest do test "can be disabled with a nil layout" do email = Email.priority_email(%{layout: nil}) - |> Email.render("password_reset_email.html", %{ + |> Email.render(:password_reset_email, %{ reset_link: "imaginary" }) diff --git a/test/workers/notify_exported_analytics_test.exs b/test/workers/notify_exported_analytics_test.exs index b3caecbe075d..c869c909cd9c 100644 --- a/test/workers/notify_exported_analytics_test.exs +++ b/test/workers/notify_exported_analytics_test.exs @@ -27,6 +27,7 @@ defmodule Plausible.Workers.NotifyExportedAnalyticsTest do assert_receive {:delivered_email, email} assert email.html_body =~ "was unsuccessful." + assert email.text_body =~ "was unsuccessful." end end end