antiwork/gumroad · error · Installment::PreviewEmailError

You have to confirm your email address before you can do tha

Error message

You have to confirm your email address before you can do that.

What it means

Raised as Installment::PreviewEmailError (defined at app/models/installment.rb:1088) by Installment#send_preview_email when the recipient user has_unconfirmed_email? — i.e. unconfirmed_email is present or the user is not confirmed (User#has_unconfirmed_email?, app/models/user.rb:1132). Previews go to the seller's own address, so an unconfirmed address means the preview cannot be delivered. Controllers rescue this error and render its message as 422 (see app/controllers/api/internal/installments/preview_emails_controller.rb:14).

Source

Thrown at app/models/installment.rb:407

    checkout_url ||= default_checkout_url

    doc = Nokogiri::HTML.fragment(message_with_inline_syntax_highlighting_and_upsells)
    doc.search("#{PRODUCT_LIST_PLACEHOLDER_TAG_NAME}").each do |node|
      node.replace(
        ApplicationController.renderer.render(
          template: "posts/abandoned_cart_products_list",
          layout: false,
          assigns: { products: },
        )
      )
    end
    doc.search("a[href='#{default_checkout_url}']").each { _1["href"] = checkout_url } if default_checkout_url != checkout_url
    doc.to_html
  end

  def send_preview_email(recipient_user)
    if recipient_user.has_unconfirmed_email?
      raise PreviewEmailError, "You have to confirm your email address before you can do that."
    elsif abandoned_cart_type?
      CustomerMailer.abandoned_cart_preview(recipient_user.id, id).deliver_later
    else
      recipient = { email: recipient_user.email }
      recipient[:url_redirect] = UrlRedirect.find_or_create_by!(installment: self, purchase: nil) if has_files?
      begin
        PostEmailApi.process(post: self, recipients: [recipient], preview: true)
      rescue ResendApiResponseError, SendGridApiResponseError
        # Either provider can be the one that actually sends this preview: the
        # recipient's domain decides (see
        # MailerInfo::UNITED_INTERNET_RECIPIENT_DOMAINS), as does the random
        # split, so a failure from either has to become the same friendly error
        # rather than an unhandled 500 on the preview request.
        raise PreviewEmailError, "Failed to send preview email. Please try again later."
      end
    end
  end

View on GitHub (pinned to afeacbd394)

Solutions

  1. Confirm the email address first: resend the confirmation email from account settings and click the link, then retry the preview.
  2. If the address was recently changed, confirm the new address to clear unconfirmed_email.
  3. Gate the 'Send preview' button on user.confirmed? && user.unconfirmed_email.blank? client-side.
  4. Handle Installment::PreviewEmailError as 422 with its message — it is a user-actionable error, not a 500.

Example fix

# before
installment.send_preview_email(current_seller) # PreviewEmailError

# after
if current_seller.has_unconfirmed_email?
  return { error: "Confirm your email address before sending a preview." }
end
installment.send_preview_email(current_seller)
Defensive patterns

Strategy: validation

Validate before calling

return { error: "Confirm your email first." } if recipient_user.has_unconfirmed_email?

Try / catch

begin
  installment.send_preview_email(user)
rescue Installment::PreviewEmailError => e
  render json: { message: e.message }, status: :unprocessable_entity
end

Prevention

When it happens

Trigger: POST to the installment preview-email endpoints (Api::Internal::Installments::PreviewEmailsController#create or Api::V2::EmailsController preview) with the acting user — current_seller, or the impersonating user when impersonation is active — unconfirmed or holding a pending unconfirmed_email (address-change flow).

Common situations: New seller never clicked the confirmation link and immediately tries to preview a post/workflow email; seller just changed their email address (unconfirmed_email set) and previews before confirming; admin impersonating an unconfirmed seller.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/5638e7849f675e5c. Report an issue: GitHub.