Rails app cannot send email. ECONNREFUSED port 25

Hi,

I’ve been struggling with my Rails app that cannot send an email. The monitoring log says it can’t connect to port 25.

2023-03-31T03:19:25.975 app[3287454ea55785] sin [info] [e77a58a2-f629-4544-8c7b-1724ed63f663] Errno::ECONNREFUSED (Connection refused - connect(2) for 127.0.0.1:25):

2023-03-31T03:19:25.975 app[3287454ea55785] sin [info] [e77a58a2-f629-4544-8c7b-1724ed63f663]

2023-03-31T03:19:25.975 app[3287454ea55785] sin [info] [e77a58a2-f629-4544-8c7b-1724ed63f663] app/mailers/user_mailer.rb:13:in `welcome_email'

2023-03-31T03:19:25.975 app[3287454ea55785] sin [info] [e77a58a2-f629-4544-8c7b-1724ed63f663] app/controllers/root_controller.rb:10:in `create'

Inside root_controller.rb

class RootController < ApplicationController
  def create

    # Get the email parameters from the request parameters
    to = params[:to]
    subject = params[:subject]
    body = params[:body]

    # Use ActionMailer to create and send the email
    email = UserMailer.welcome_email.deliver_now

    # Check if the email was successfully sent or not
    if email.delivered?
      flash[:notice] = "Email sent successfully to #{to}"
    else
      flash[:alert] = "Failed to send email to #{to}"
    end

    # Redirect to the root URL
    redirect_to root_url


  end
end

Inside the user_mailer.rb

class UserMailer < ApplicationMailer
    default from: 'notifications@example.com'

    def welcome_email
        recipient_email = 'mytest_xxx@gmail.com'
        # Use the `mail` gem to send the email
        mail = Mail.new do
          from     'your_email@example.com'
          to       recipient_email
          subject  'Test email'
          body     'This is a test email sent from my Rails app.'
        end
        mail.deliver!
        redirect_to root_path, notice: 'Email sent successfully!'
    end
end

I checked these threads and they said fly.io already allowed SMTP port 25:

This is what’s inside my fly.toml:

[[services]]
  internal_port = 25
  protocol = "tcp"

  [[services.ports]]
    port = 25

  [[services.ports]]
    handlers = ["tls"]
    port = 465

  [[services.ports]]
    port = 587

    
[[services]]
  internal_port = 3000
  processes = ["app"]
  protocol = "tcp"
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

[[statics]]
  guest_path = "/rails/public"
  url_prefix = "/"

I even tried to use sendgrid, edited the production.rb but nothing helps so I reverted it.

I also inserted the MAIL_HOST env:

# env | grep -i mail
MAIL_HOST=smtp.sendgrid.net

First, my read of the yaml is that you are exposing 4 ports externally, 465, 567, 80, and 433, and mapping them internally to ports 25 and 3000, the first two to 25, the latter two to 3000. I’m just mentioning this for completeness as this appears intentional and correct - if that’s what you want.

What that would do is set things up for you to receive (not send, receive) email on 465 and 567. But only if your application were listening on port 25. Port 25 is a privileged port so to listen on that port you would need to run as root. I doubt that that is what you want to do, but should you want to pursue that, bin/rails generate dockerfile --root will make the necessary changes.

Sending an email is a complicated topic having nothing to do with Rails, and having everything to do with spammers. If you own your own DNS domain, you there are a number of ways to set things up, but this is not easy.

The easy path is to start with gmail. Most people have a gmail account, if not they are easy to obtain. Follow these directions, and be sure to read the note and set an app password.

Once you have that working, feel free to change to sendgrid or another email provider.

A final note, you don’t want to commit your smtp credentials to git. I recommend putting them into your credentials via 'bin/rails credentials:edit`.

I have an app that does this, using my own domain, and my credentials look like:

smtp:
  address: 'smtp.dreamhost.com'
  ssl: true
  port: 465
  user_name: 'rubys@intertwingly.net'
  password: '<REDACTED>'

This enabled your configuration to be reduced to:

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = Rails.application.credentials.smtp

Thanks for your help. I restored the original fly.toml and here’s what I have now:

# fly.toml file generated for bold-surf-1282 on 2023-03-31T21:44:38+08:00

app = "bold-surf-1282"
kill_signal = "SIGINT"
kill_timeout = 5
mounts = []
primary_region = "sin"
processes = []

[[services]]
  internal_port = 3000
  processes = ["app"]
  protocol = "tcp"
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

[[statics]]
  guest_path = "/rails/public"
  url_prefix = "/"

So I decided to use SMTP method instead (not using credentials for now to test if it works). This is my configs/environment/production.rb:

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:              'smtp-relay.sendinblue.com',
    port:                 587,
    user_name:            'xxx@xxxx.com',
    password:             'xxxxxxx',
    authentication:       'plain',
    enable_starttls_auto: true
  }
  

Then I deployed the app it looks like it’s still using port 25.

2023-03-31T14:02:07.494 app[9080521f643d87] sin [info] [7e86a550-e972-4d77-8bd9-79aecbd8c25b] Errno::ECONNREFUSED (Connection refused - connect(2) for 127.0.0.1:25):

2023-03-31T14:02:07.494 app[9080521f643d87] sin [info] [7e86a550-e972-4d77-8bd9-79aecbd8c25b]

2023-03-31T14:02:07.494 app[9080521f643d87] sin [info] [7e86a550-e972-4d77-8bd9-79aecbd8c25b] app/mailers/user_mailer.rb:15:in `welcome_email'

2023-03-31T14:02:07.494 app[9080521f643d87] sin [info] [7e86a550-e972-4d77-8bd9-79aecbd8c25b] app/controllers/root_controller.rb:5:in `create'

I even force it to use SMTP in user_mailer.rb self.delivery_method = :smtp

class UserMailer < ApplicationMailer
    self.delivery_method = :smtp

    default from: 'notifications@example.com'

    def welcome_email
        recipient_email = 'xxxx@gmail.com'
        # Use the `mail` gem to send the email
        mail = Mail.new do
          from     'your_email@example.com'
          to       recipient_email
          subject  'Test email'
          body     'This is a test email sent from my Rails app.'
        end
        mail.deliver!
        redirect_to root_path, notice: 'Email sent successfully!'
    end
end

So I’m not sure why it’s not using the custom SMTP settings. Something is on this app that’s forcing that port 25.

I already setup the MAIL_HOST

22:10:05 ~/fly.io/rails $ fly ssh console
Connecting to fdaa:1:ca5a:a7b:a755:b99b:28c7:2... complete
# env | grep -i mail
MAIL_HOST=smtp-relay.sendinblue.com

Try overriding the address on the individual mail itself by adding a call immediately before your deliver line:

mail.delivery_method :smtp, {
  address:              'smtp-relay.sendinblue.com',
  port:                 587,
  user_name:            'xxx@xxxx.com',
  password:             'xxxxxxx',
  authentication:       'plain',
  enable_starttls_auto: true
}

mail.deliver!

That can be a permanent fix (it is actually how I do it in my app), but if not the next puzzle would be to determine why the configuration is not being picked up.

@rubys Yep, that works. Thanks again and have a good day!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.