Skip to content

Emails

Rails
Status ✅
Code app/mailers/, app/views/{auth_mailer,account_mailer,trip_created_mailer,beta_mailer,support_request_mailer,reply_mailer,mailers}/, config/locales/{en,de}.yml (mailers.*)

Verified against code: 2026-10-20

Purpose

SailEver sends a few transactional emails: sign-in links, email-address changes, one email per new trip, the beta invitation, the admin notices about beta sign-ups and support requests, and the support reply. There is no newsletter and no per-track email.

General rules

  • Sender: SailEver <no-reply@sailever.com> for every email. The support reply adds Reply-To: support@sailever.com; the admin notification replies to the requester.
  • Links point to the first web host (SAILEVER_WEB_HOSTS, beta: https://beta.sailever.com); without one, to https://sailever.com in production (README.md).
  • Delivery: production sends over SMTP to OCI Email Delivery (no-reply@sailever.com is its approved sender); a delivery error raises. Development opens mails in the browser (letter_opener), tests collect them.
  • Every email has an HTML and a plain-text part.
  • User emails are rendered in the user's preferred language (users.locale), falling back to English. Links carry that locale. Missing texts fall back to English (i18n.md).
  • Links that sign the user in are magic links: valid 30 minutes, usable once. Opening one shows a confirm page; its "Sign in" button signs in (auth.md).
  • The HTML part uses the shared layout layouts/mailer.html.erb (with a width=device-width viewport): a centred 600 px column with the SailEver logo on top (120 × 50 px, alt text "SailEver"), and a blue button (mailers/_button). Styles are inline.
  • The logo is https://assets.sailever.com/email/logo.png (SAILEVER_ASSETS_URL + /email/logo.png; orange on transparent, readable in light and dark mail clients). That URL never changes, so sent emails keep their logo through the move from beta to www (infra/assets). Without SAILEVER_ASSETS_URL (development, tests) the logo comes from the app.

Overview

Email Mailer Trigger To
Magic link AuthMailer#magic_link Sign-in requested User
Confirm new address AccountMailer#confirm_email New address saved on the account page New address
Address change notice AccountMailer#email_change_requested Same Current address
Account deleted AccountMailer#deleted AccountErasureJob, before the account is erased The account's address
New trip TripCreatedMailer#created A new trip's first track is complete User
Beta invitation BetaMailer#invitation_email Admin clicks "Invite" Applicant
Beta sign-up notification BetaMailer#application_received A new email address signs up on /beta Every admin
Support request notification SupportRequestMailer#support_request_created Support form sent Oldest admin
Support reply ReplyMailer#reply_sent Admin sends a reply Requester
Part Content
Subject "Your SailEver Sign-in Link"
Heading Logo / "Your Sign-in Link"
Body "Click the button below to sign in to your SailEver account. This link will expire in 30 minutes."
Button "Sign in to SailEver" → /<locale>/auth/magic_link/callback?token=…
Fallback "Or copy and paste this URL into your browser:" + the URL
Footer "If you did not request this email, you can safely ignore it."

Sent immediately (not queued). The link's redirect target is kept in the token, not in the URL.

Email change

Both are queued when a new address is saved (auth.md).

Confirm new address (to the new address):

Part Content
Subject "Confirm your new SailEver address"
Body "Click the button to sign in to SailEver with from now on. Until then your old address keeps working."
Button "Confirm this address" → /<locale>/my/account/email/confirm?token=… (valid 24 hours)
Footer "The link works for 24 hours. If you didn't ask for this, ignore this email."

Notice (to the current address):

Part Content
Subject "Your SailEver address is about to change"
Body "Someone asked to change the sign-in address of your SailEver account to . Nothing changes until the link sent there is clicked; until then this address keeps working."
Footer "Wasn't you? Sign in and change the address back, or reply to this email."

Account deleted

Sent by AccountErasureJob right before it erases the account (auth.md, admin.md), at once (not queued again). The mailer gets the address and language, not the user, because the row is gone right after. English and German texts.

Part Content
Subject "Your SailEver account is deleted"
Body "As you asked, we are deleting your SailEver account now: your trips, tracks, boats and devices, your passkeys, and your support requests and beta application. Watches paired with the account no longer upload. You won't hear from us again."
Footer "Didn't ask for this? Reply to this email. We can't bring the data back, but we want to know."

New trip

One email per trip, never one per track.

Rule Value
Sent when The trip's first track is complete: a FIT file is processed, or an SLTB track is fully synced. Checked after every import, upload and recompute.
Sent once Only while trips.import_notified_at is empty; it is set in the same atomic update, so concurrent jobs send one mail. Later tracks, trims and recomputes send nothing.
Queued Yes (deliver_later)
Part Content
Subject " is in your logbook"
Heading Logo / "New trip in your logbook"
Card Trip title, then three tiles in one row: distance " NM" (blue) "Distance", sailing hours " h" (blue) "Sailing", engine hours " h" (red #ef4444) "Engine". The row fits a 320 px phone screen: fixed table layout, 6 px between tiles, 12 px / 4 px tile padding, 20 px values whose unit wraps under the number when it has to, 16 px card padding.
Button "Open the trip" → magic link that signs the user in and opens /<locale>/my/trips/:id
Under the button "The button signs you in and opens the trip."
Footer "Recorded with SailEver"

The values are the stored numbers as they are (e.g. 42.53, 5.5), not the web formats.

Beta invitation

Part Content
Subject "Your Invite to the SailEver Beta ⛵"
Body "Welcome aboard the SailEver Beta! ⛵", "Hi ,", "Your access to the private SailEver Web Platform has been approved!", "You can now link your Garmin watch and upload your recorded sailing trips (.FIT files) directly to your personal logbook."
Button "Activate Your Account & Pair Watch" → magic link that signs in and opens /pair
Fallback The URL as text
Signature "Fair winds, Jakob & The SailEver Team"

Sent immediately. The body is English on every locale (not in the locale files).

Beta sign-up notification

Part Content
To Every user with admin (one email, all admins in To, oldest account first); not sent when there is no admin
From / Reply-To no-reply@sailever.com / the applicant's email
Subject "New beta sign-up: "
Body "New beta sign-up", then Name, Email, Watch, Signed up (date %B %e, %Y %H:%M) and Why ("—" when watch or reason is empty)
Button "Review and invite" → the applicant in the admin area (/admin/beta_applicants/<id>)

Sent in the background after the sign-up is saved, only for a new email address: sending the form again with the same address updates the applicant without a second email. English, like the admin area (not in the locale files).

Support request notification

Part Content
To The email of the oldest user with admin; not sent when there is no admin
From / Reply-To no-reply@sailever.com / the requester's email
Subject "New Support Request - SailEver"
Body "A new support request has been submitted on the SailEver website:", then Name, Email, Topic, Message, Submitted (date %B %e, %Y %H:%M), "Please respond to this request at your earliest convenience."
Footer "This email was automatically generated by the SailEver support system."

Sent immediately. A delivery error is logged and doesn't stop the request from being saved.

Support reply

Part Content
To / From / Reply-To The requester / no-reply@sailever.com / support@sailever.com
Subject The subject typed by the admin (default "#: Re: ")
Body Header "SailEver Support Response", "Hello ,", "Thank you for contacting SailEver support.", the reply text, the original request (topic, message, "Submitted on "), "If you have any additional questions, please feel free to reply to this email."
Footer "SailEver - Your Ultimate Sailing Companion", support email, website https://www.sailever.com

Sent immediately when the admin replies (admin.md). Rendered in the admin's locale (English).

States and edge cases

  • Requesting several sign-in links sends several emails; each link works once (rate limit in auth.md).
  • A user without a locale gets English.

Known deviations

  • The magic links in the new-trip email and the beta invitation expire after 30 minutes, like a sign-in link. A user who opens the email later lands on the sign-in page with "This link has expired. Enter your email and we'll send you a new one." and the target kept, so signing in again opens the trip (auth.md); already signed in, the link opens the trip directly.
  • The beta invitation has no WatchApp store link, although the install guide says "Your invite email has the install link". Its copy says "link your Garmin watch" and "Web Platform".
  • The new-trip email shows raw decimals and decimal hours instead of the web formats.
  • The new-trip engine tile uses #ef4444, not the website's --engine token (vessel-state.md).
  • Support mails use their own styles (#0066cc, #0d6efd), not the SailEver look.