Browser-local evidence planner
Start with the first safe account check
No email address, account ID, reset URL, token, message body, SMTP value, provider key, event payload, or mailbox content is requested or transmitted.
- Boundary
- Next action
- Exit condition
- Safety
The six evidence boundaries
- 1. Account destination
- The stored User email must privately match the intended Gmail account and must not be an application placeholder.
- 2. Reset persistence
- The exact account's
reset_password_sent_atmust advance for one controlled request. - 3. Rails delivery
- The deployed Devise path must produce one bounded Action Mailer failure or one SMTP handoff.
- 4. Provider event
- The actual relay must record the same private Message-ID as accepted, failed, suppressed, or delivered.
- 5. Gmail visibility
- Receiver acceptance and mailbox visibility are different states.
- 6. Link completion
- The newest single-use reset link must be tested separately from delivery.
Never paste a member address, account row, reset timestamp tied to a person, reset URL, token, raw Action Mailer log, SMTP value, provider event payload, API key, or mailbox screenshot into a public issue.
What the current TimeOverflow source proves
At TimeOverflow develop revision ddaec8a77e24e2595c9fbfc9e9a25627fe3ecdab, User includes Devise :recoverable. The application uses Rails 7.2.3 and Devise 4.9.4, does not override send_devise_notification, and configures general Action Mailer background work to use Sidekiq.
Those facts do not put password-reset mail in Sidekiq. Devise 4.9.4's default password controller calls User.send_reset_password_instructions; Recoverable writes the token digest and reset_password_sent_at, then its default notification path calls deliver_now. For this revision, watch the Rails web request and SMTP handoff before inspecting the Sidekiq mailers queue.
The same User model can generate user<ID>@example.com placeholders for records created without an email. That makes private account mapping the first boundary for a member-specific report. A Gmail address supplied in a support ticket does not prove that the affected User row currently stores it.
This is source evidence for the cited revision, not production-state evidence. A private deployment patch, different revision, or custom mailer can change the path.
Check the account without emitting the address
Run this privately with the affected internal User ID. It returns booleans and the reset timestamp, not the address. Keep even this output private when it can be tied to a person.
bundle exec rails runner '
u = User.find(ACCOUNT_ID)
puts({
real_email: u.has_valid_email?,
confirmed: u.confirmed?,
reset_sent_at: u.reset_password_sent_at&.utc&.iso8601
}.to_json)
'
If real_email is false or the stored value does not privately match the intended Gmail address, repair the User through the normal administrator workflow first. Preserve Devise reconfirmation behavior rather than editing the database around it.
Inspect effective mail configuration without values
TimeOverflow's production configuration builds smtp_settings from runtime SMTP_* variables and obtains the Devise sender and reset-link host separately. This presence-only command reports the effective delivery mode and booleans without printing credentials, addresses, or hosts:
bundle exec rails runner '
c = Rails.application.config.action_mailer
s = c.smtp_settings || {}
puts({
delivery_method: c.delivery_method,
perform_deliveries: c.perform_deliveries,
raise_delivery_errors: c.raise_delivery_errors,
smtp_address_present: s[:address].present?,
smtp_port_present: s[:port].present?,
smtp_username_present: s[:user_name].present?,
smtp_password_present: s[:password].present?,
sender_present: Devise.mailer_sender.present?,
sender_is_example_default: Devise.mailer_sender.include?("example.com"),
link_host_present: c.default_url_options[:host].present?
}.to_json)
'
A true presence flag does not prove syntax, authorization, TLS, or deliverability. It only prevents configuration guesses from jumping ahead of the running process.
Trace one controlled request
- Privately record the current
reset_password_sent_atand one UTC start time. - Request one reset for the exact account. Do not repeat the request while the first message is queued or under review.
- Confirm that the timestamp advanced. If it did not, stay at account lookup, routing, validation, or deployment identity.
- In the Rails web process, retain only
mailer,action, private Message-ID, duration,perform_deliveries, and exception class. Raw debug mail output can contain the recipient and reset link. - Use the private Message-ID and UTC window to locate one provider event.
Rails 7.2 reports a successful immediate send as Delivered mail <Message-ID>. That proves the configured delivery agent returned successfully; it does not prove that Gmail accepted the message or placed it in an inbox.
Privacy-safe Action Mailer instrumentation
A deliver.action_mailer subscriber can record the bounded result without logging the :mail payload:
ActiveSupport::Notifications.subscribe("deliver.action_mailer") do |event|
payload = event.payload
Rails.logger.info({
event: "mail_delivery",
mailer: payload[:mailer],
action: payload[:action],
message_id: payload[:message_id],
duration_ms: event.duration.round,
perform_deliveries: payload[:perform_deliveries],
exception_class: payload[:exception]&.first
}.to_json)
end
Keep the Message-ID private or redact it in public discussion. Do not serialize payload[:mail], exception_object, parameters, headers, recipient, or body.
Separate provider acceptance from Gmail acceptance
Public DNS for timeoverflow.org currently includes Mailgun in SPF and points inbound MX to Mailgun, but only the running SMTP configuration proves the outbound provider. If that provider is Mailgun, follow the private Message-ID in Logs or the Events API:
- accepted
- Mailgun accepted and queued the request. This is not Gmail acceptance.
- rejected
- Mailgun rejected the request before queueing.
- failed
- Use the temporary or permanent failure and suppression reason as the next boundary.
- delivered
- The recipient email server accepted the message. This still does not prove inbox placement.
If Rails reports a handoff but the expected Mailgun account has no event, verify the actual SMTP endpoint, US or EU region, account, sending domain, deployment, and Message-ID before changing Gmail or DNS.
Check Gmail only after receiver evidence
After the provider records Gmail receiver acceptance, search the controlled account in All Mail and Spam using the private Message-ID, sender, and narrow UTC window. Then inspect filters, forwarding, storage and account security controls. Do not create another reset token while tracing the accepted instance.
Google requires all senders to authenticate with SPF or DKIM, use valid forward and reverse DNS for sending infrastructure, and transmit with TLS. It recommends SPF, DKIM, and DMARC for each sending domain. These controls improve trust, but none can guarantee the Primary tab or inbox placement.
A separate public DNS defect to verify against the actual From domain
A public scan at 2026-07-23T19:41:33Z returned two DMARC Policy Records at _dmarc.timeoverflow.org: one p=quarantine record and one p=none record. RFC 9989 discards all DMARC Policy Records when a single lookup target returns more than one.
If the running MAILER_SENDER uses timeoverflow.org, merge the DNS state into exactly one intentional record and verify SPF or DKIM alignment from a delivered message header. If the visible From uses another domain, inspect that domain instead. The duplicate record is a real configuration defect, but it is not proof of why this one Gmail message is missing.
Make the repair observable and testable
- Add a request test proving the exact User's reset timestamp advances and one reset notification is attempted.
- Keep public account-enumeration behavior generic while recording an internal no-account, render-failed, SMTP-failed, or handoff outcome.
- Make
perform_deliveriesandraise_delivery_errorsintentional production settings, and fail readiness when required sender, link-host, or SMTP keys are absent. - Record privacy-safe Action Mailer outcomes and provider webhooks with a stable correlation reference and idempotent state transitions.
- Alert when reset requests have no mail outcome, provider acceptance has no terminal event, or failures exceed a bounded threshold.
- Monitor Sidekiq only if the application deliberately overrides Devise to call
deliver_later.
Read the four-section version 1.1.0 sample first. The complete 14-section Web3 Email Authentication Operations Kit costs exactly 1 native USDC on Base Mainnet only when it is useful to you.
The production-ready proof
Call this incident resolved only when the exact private account mapping is correct, one reset timestamp advances, Rails records one synchronous delivery result, the provider records the same message, Gmail visibility is known, and the newest link succeeds or has its own bounded failure. Keep every recipient, token, URL, credential, and message body outside public evidence.
This independent guide is not affiliated with TimeOverflow, Devise, Ruby on Rails, Mailgun, or Google. The private User record, deployed revision, Rails event, provider event, Gmail account, and reset route remain the sources of truth for their own boundaries.
Primary references
- TimeOverflow issue 849: Gmail password-reset email not received
- TimeOverflow revision: Devise modules and placeholder email behavior
- TimeOverflow revision: Active Job and mailers queue configuration
- TimeOverflow revision: SMTP settings and link host
- Devise 4.9.4 Recoverable: token persistence and notification
- Devise 4.9.4 Authenticatable: default deliver_now path
- Devise 4.9.4 password controller
- Ruby on Rails: Action Mailer basics and delivery configuration
- Rails 7.2 Action Mailer delivery log payload
- Mailgun: accepted, rejected, delivered, and failed events
- Mailgun: temporary, permanent, suppression, and delayed failures
- Google: email sender guidelines
- RFC 9989: DMARC Policy Record discovery and duplicate-record handling