neiam
/diogramos
diogramos
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
a good email setup
eb57556 · gmorell · 2026-04-30 01:12
Files changed
modified
config/config.exs
+4
−1
@@ -53,7 +53,10 @@ config :diogramos, DiogramosWeb.Endpoint,
| 53 | 53 | # |
| 54 | 54 | # For production it's recommended to configure a different adapter |
| 55 | 55 | # at the `config/runtime.exs`. |
| 56 | −config :diogramos, Diogramos.Mailer, adapter: Swoosh.Adapters.Local | |
| 56 | +config :diogramos, Diogramos.Mailer, | |
| 57 | + adapter: Swoosh.Adapters.Local, | |
| 58 | + from_name: "Diogramos", | |
| 59 | + from_address: "noreply@localhost" | |
| 57 | 60 | |
| 58 | 61 | # Configure esbuild (the version is required) |
| 59 | 62 | config :esbuild, |
modified
config/runtime.exs
+25
−8
@@ -105,20 +105,33 @@ if config_env() == :prod do
| 105 | 105 | |
| 106 | 106 | # Mailer adapter selection: |
| 107 | 107 | # |
| 108 | − # * MAILGUN_API_KEY + MAILGUN_DOMAIN → Swoosh.Adapters.Mailgun | |
| 109 | − # * otherwise → Swoosh.Adapters.Logger | |
| 108 | + # * SMTP_RELAY set → Swoosh.Adapters.SMTP (gen_smtp) | |
| 109 | + # * otherwise → Swoosh.Adapters.Logger | |
| 110 | 110 | # |
| 111 | 111 | # The Logger adapter doesn't actually send mail — it logs the |
| 112 | 112 | # rendered email at :info — but it gets us off Swoosh.Adapters.Local, |
| 113 | 113 | # which is what the login page checks for to show the dev-mailbox |
| 114 | − # banner. Wire up a real provider when you're ready to receive | |
| 115 | − # confirmation links again. | |
| 114 | + # banner. | |
| 115 | + smtp_tri = fn var, default -> | |
| 116 | + case System.get_env(var, default) do | |
| 117 | + v when v in ~w(always if_available never) -> String.to_existing_atom(v) | |
| 118 | + other -> raise "#{var} must be one of always|if_available|never, got: #{inspect(other)}" | |
| 119 | + end | |
| 120 | + end | |
| 121 | + | |
| 116 | 122 | mailer_opts = |
| 117 | − if System.get_env("MAILGUN_API_KEY") && System.get_env("MAILGUN_DOMAIN") do | |
| 123 | + if relay = System.get_env("SMTP_RELAY") do | |
| 118 | 124 | [ |
| 119 | − adapter: Swoosh.Adapters.Mailgun, | |
| 120 | − api_key: System.get_env("MAILGUN_API_KEY"), | |
| 121 | − domain: System.get_env("MAILGUN_DOMAIN") | |
| 125 | + adapter: Swoosh.Adapters.SMTP, | |
| 126 | + relay: relay, | |
| 127 | + port: String.to_integer(System.get_env("SMTP_PORT", "587")), | |
| 128 | + username: System.get_env("SMTP_USERNAME"), | |
| 129 | + password: System.get_env("SMTP_PASSWORD"), | |
| 130 | + tls: smtp_tri.("SMTP_TLS", "if_available"), | |
| 131 | + ssl: System.get_env("SMTP_SSL", "false") == "true", | |
| 132 | + auth: smtp_tri.("SMTP_AUTH", "if_available"), | |
| 133 | + retries: 1, | |
| 134 | + no_mx_lookups: false | |
| 122 | 135 | ] |
| 123 | 136 | else |
| 124 | 137 | [adapter: Swoosh.Adapters.Logger, level: :info] |
@@ -126,6 +139,10 @@ if config_env() == :prod do
| 126 | 139 | |
| 127 | 140 | config :diogramos, Diogramos.Mailer, mailer_opts |
| 128 | 141 | |
| 142 | + config :diogramos, Diogramos.Mailer, | |
| 143 | + from_name: System.get_env("MAIL_FROM_NAME", "Diogramos"), | |
| 144 | + from_address: System.get_env("MAIL_FROM_ADDRESS") || "noreply@#{host}" | |
| 145 | + | |
| 129 | 146 | config :diogramos, DiogramosWeb.Endpoint, |
| 130 | 147 | url: [host: host, port: 443, scheme: "https"], |
| 131 | 148 | # Accept both http and https origins for the configured host. The |
modified
lib/diogramos/accounts/user_notifier.ex
+5
−1
@@ -6,10 +6,14 @@ defmodule Diogramos.Accounts.UserNotifier do
| 6 | 6 | |
| 7 | 7 | # Delivers the email using the application mailer. |
| 8 | 8 | defp deliver(recipient, subject, body) do |
| 9 | + mailer_config = Application.get_env(:diogramos, Mailer, []) | |
| 10 | + from_name = Keyword.get(mailer_config, :from_name, "Diogramos") | |
| 11 | + from_address = Keyword.get(mailer_config, :from_address, "noreply@localhost") | |
| 12 | + | |
| 9 | 13 | email = |
| 10 | 14 | new() |
| 11 | 15 | |> to(recipient) |
| 12 | − |> from({"Diogramos", "contact@example.com"}) | |
| 16 | + |> from({from_name, from_address}) | |
| 13 | 17 | |> subject(subject) |
| 14 | 18 | |> text_body(body) |
| 15 | 19 |
modified
lib/diogramos_web/live/canvas_live/edit.ex
+14
−7
@@ -1899,7 +1899,7 @@ defmodule DiogramosWeb.CanvasLive.Edit do
| 1899 | 1899 | if enabled == [] do |
| 1900 | 1900 | ~H"" |
| 1901 | 1901 | else |
| 1902 | − assigns = assign(assigns, :placements, link_placements(element, enabled)) | |
| 1902 | + assigns = assign(assigns, :placements, link_placements(element, enabled, :editor)) | |
| 1903 | 1903 | |
| 1904 | 1904 | ~H""" |
| 1905 | 1905 | <%= for %{link: link, x: x, y: y, size: size, href: href, icon: icon} <- @placements do %> |
@@ -1937,7 +1937,7 @@ defmodule DiogramosWeb.CanvasLive.Edit do
| 1937 | 1937 | bottom-right corner of the element's bbox toward the left so the |
| 1938 | 1938 | "primary" (first) link is closest to the corner. |
| 1939 | 1939 | """ |
| 1940 | − def link_placements(element, enabled_links) do | |
| 1940 | + def link_placements(element, enabled_links, context \\ :embed) do | |
| 1941 | 1941 | {origin_x, origin_y, size} = link_overlay_geometry(element) |
| 1942 | 1942 | gap = 2 |
| 1943 | 1943 |
@@ -1946,7 +1946,7 @@ defmodule DiogramosWeb.CanvasLive.Edit do
| 1946 | 1946 | |> Enum.map(fn {link, i} -> |
| 1947 | 1947 | %{ |
| 1948 | 1948 | link: link, |
| 1949 | − href: link_href(link), | |
| 1949 | + href: link_href(link, context), | |
| 1950 | 1950 | icon: link_icon_id(link["icon"]), |
| 1951 | 1951 | x: origin_x - i * (size + gap), |
| 1952 | 1952 | y: origin_y, |
@@ -1978,11 +1978,18 @@ defmodule DiogramosWeb.CanvasLive.Edit do
| 1978 | 1978 | def link_icon_id(name), do: "dx-link-icon-#{name || "link"}" |
| 1979 | 1979 | |
| 1980 | 1980 | @doc false |
| 1981 | − def link_href(%{"kind" => "canvas", "target" => slug}) when is_binary(slug) and slug != "", | |
| 1982 | − do: "/c-embed/#{slug}" | |
| 1981 | + def link_href(link, context \\ :embed) | |
| 1983 | 1982 | |
| 1984 | − def link_href(%{"target" => target}) when is_binary(target), do: target | |
| 1985 | − def link_href(_), do: "#" | |
| 1983 | + def link_href(%{"kind" => "canvas", "target" => slug}, :editor) | |
| 1984 | + when is_binary(slug) and slug != "", | |
| 1985 | + do: "/c/#{slug}" | |
| 1986 | + | |
| 1987 | + def link_href(%{"kind" => "canvas", "target" => slug}, _context) | |
| 1988 | + when is_binary(slug) and slug != "", | |
| 1989 | + do: "/c-embed/#{slug}" | |
| 1990 | + | |
| 1991 | + def link_href(%{"target" => target}, _context) when is_binary(target), do: target | |
| 1992 | + def link_href(_, _context), do: "#" | |
| 1986 | 1993 | |
| 1987 | 1994 | attr :element, :map, required: true |
| 1988 | 1995 | attr :element_id, :string, required: true |
modified
lib/diogramos_web/live/canvas_live/embed.ex
+1
−1
@@ -493,7 +493,7 @@ defmodule DiogramosWeb.CanvasLive.Embed do
| 493 | 493 | assign( |
| 494 | 494 | assigns, |
| 495 | 495 | :placements, |
| 496 | − DiogramosWeb.CanvasLive.Edit.link_placements(element, enabled) | |
| 496 | + DiogramosWeb.CanvasLive.Edit.link_placements(element, enabled, :embed) | |
| 497 | 497 | ) |
| 498 | 498 | |
| 499 | 499 | ~H""" |
modified
mix.exs
+1
−0
@@ -60,6 +60,7 @@ defmodule Diogramos.MixProject do
| 60 | 60 | compile: false, |
| 61 | 61 | depth: 1}, |
| 62 | 62 | {:swoosh, "~> 1.16"}, |
| 63 | + {:gen_smtp, "~> 1.2"}, | |
| 63 | 64 | {:req, "~> 0.5"}, |
| 64 | 65 | {:telemetry_metrics, "~> 1.0"}, |
| 65 | 66 | {:telemetry_poller, "~> 1.0"}, |
modified
mix.lock
+2
−0
@@ -16,6 +16,7 @@
| 16 | 16 | "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, |
| 17 | 17 | "finch": {:hex, :finch, "0.21.0", "b1c3b2d48af02d0c66d2a9ebfb5622be5c5ecd62937cf79a88a7f98d48a8290c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "87dc6e169794cb2570f75841a19da99cfde834249568f2a5b121b809588a4377"}, |
| 18 | 18 | "fine": {:hex, :fine, "0.1.6", "4bf7151493443c454aac9f2fa2f34f5fefd0346a83fb5586a016c4a135c63247", [:mix], [], "hexpm", "5638eb4495488e885ebec167fa57973e5c35e1a50c344eb7666c90ec1c4e3b12"}, |
| 19 | + "gen_smtp": {:hex, :gen_smtp, "1.3.0", "62c3d91f0dcf6ce9db71bcb6881d7ad0d1d834c7f38c13fa8e952f4104a8442e", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "0b73fbf069864ecbce02fe653b16d3f35fd889d0fdd4e14527675565c39d84e6"}, | |
| 19 | 20 | "gettext": {:hex, :gettext, "1.0.2", "5457e1fd3f4abe47b0e13ff85086aabae760497a3497909b8473e0acee57673b", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "eab805501886802071ad290714515c8c4a17196ea76e5afc9d06ca85fb1bfeb3"}, |
| 20 | 21 | "hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"}, |
| 21 | 22 | "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]}, |
@@ -46,6 +47,7 @@
| 46 | 47 | "plug": {:hex, :plug, "1.19.1", "09bac17ae7a001a68ae393658aa23c7e38782be5c5c00c80be82901262c394c0", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "560a0017a8f6d5d30146916862aaf9300b7280063651dd7e532b8be168511e62"}, |
| 47 | 48 | "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, |
| 48 | 49 | "postgrex": {:hex, :postgrex, "0.22.0", "fb027b58b6eab1f6de5396a2abcdaaeb168f9ed4eccbb594e6ac393b02078cbd", [:mix], [{:db_connection, "~> 2.9", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a68c4261e299597909e03e6f8ff5a13876f5caadaddd0d23af0d0a61afcc5d84"}, |
| 50 | + "ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"}, | |
| 49 | 51 | "req": {:hex, :req, "0.5.17", "0096ddd5b0ed6f576a03dde4b158a0c727215b15d2795e59e0916c6971066ede", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0b8bc6ffdfebbc07968e59d3ff96d52f2202d0536f10fef4dc11dc02a2a43e39"}, |
| 50 | 52 | "sentry": {:hex, :sentry, "10.10.0", "d058b635f3796947545c8057a42996f6dbefd12152da947209b56d16af41b161", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c7ddd3cfdd63fcee53b1e28f9a653037e6927b2b1dbd300b7aeee9687c7a8f6"}, |
| 51 | 53 | "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, |
Parents: 7faf5f7