0

Problem Summary

I'm having problems with the Ruby mailfactory gem (or Net::SMTP) when I try to include addresses into the CC field. I'm not sure which of the two I might be using incorrectly.

Both test/production systems have the same version for mailfactory, but different versions for the Ruby installation. I'm using mailfactory (1.4.0). The test system has ruby 2.1.2p95 (2014-05-08) [x86_64-linux-gnu] and the production system has ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux].

Current Code

This is the code I have in my email-sending function:

mail = MailFactory.new

to_addr   = 'to@domain.com'
cc_addr   = ['cc1@domain.com', 'cc2@domain.com']
#
# ...ommitted for brevity...
#
mail.to       = to_addr
mail.cc       = cc_addr.join ';'
mail.from     = 'from@domain.com'
mail.subject  = "Subject here"
mail.text     = "Some text here"
mail.html     = "Some HTML text here"

Net::SMTP.start('smtp-host@domain.com', 25) do |smtp|
  smtp.send_message(mail.to_s, mail.from.to_s, to_addr)
end

The code above works, but only partially. Those in the CC list seem to receive the emails when I run my tests (and only sometimes), but when the code runs in production, no one in the CC list seems to receive the copies. (I happen to be in the CC list and I never get any of them.)

I've tried a few different things, including joining to_addr and cc_addr into a single string, as follows:

cc_addr << to_addr
Net::SMTP.start('smtp-host@domain.com', 25) do |smtp|
  smtp.send_message(mail.to_s, mail.from.to_s, cc_addr.join(';'))
end

This did not work, either.

I also tried using mailfactory's add_header method:

mail.add_header('To', to_addr)
mail.add_header('Cc', cc_addr.join(';'))
mail.add_header('From', "from@domain.com")
# etc...

This did not work, either. Addresses in the CC list don't get the messages (not even in the test environment, which used to work). In fact, even if the CC contains a single string, it still doesn't work.

Other Observations

Here're a few more things I've directly observed:

  1. When I puts mail.to_s to the terminal, the mail headers appear to be OK (i.e. I see the addresses, including CCs -see samples below);

  2. When a user replies to one of the emails received, all the addresses are clearly listed in the CC fields, even though no one seems to have received them (at least I know I didn't);

  3. The same SMTP server (IT-managed) is used by other non-Ruby programs to send emails, including CCs, and there're no issues;

  4. The program runs normally (i.e. no warnings or error messages show up);

  5. The email addresses are valid, even though I once got a mail delivery notification failure for one such address (have not seen that again, seemed to be a one-time issue on the IT side)

  6. Trying to join several addresses into the To: field does not work. (The source code seems to limit the to field to a single address.)

I had already checked other references/examples, but they're very simplistic and focus on a single To:, From:, etc. Since that already seems to work for me, they're of no use.

Header Sample 1

Here're the actual email headers, as produced by puts mail.to_s, with addresses and domain edited for obvious reasons.

The headers below were produced with the use of

mail.add_header('To:', 'to@domain.com')
mail.add_header('From:', 'from@domain.com')
mail.add_header('Cc:', 'cc1@domain.com')

...and so on. The output was:

To: to@domain.com
From: from@domain.com
Cc: cc1@domain.com
Cc: cc2@domain.com
Reply-to: from@domain.com
Subject: The subject
Message-ID: <1455811642.9742095.1000.11119260@domain.com>
Date: Thu, 18 Feb 2016 08:07:22 -0800
MIME-Version: 1.0
Content-Type: multipart/alternative;boundary="----=_NextPart_APX_H3L1_qoWN58XIkVGr5SL_"

Header Sample 2

The headers below were produced with the use of

mail.to = 'to@domain.com'
mail.cc = cc_addr.join ';'

...and so on. They produced:

to: to@domain.com
cc: cc1@domain.com;cc2@domain.com
from: from@domain.com
subject: =?utf-8?Q?The_subject?=
Message-ID: <1455812736.522942.1000.7983900@domain.com>
Date: Thu, 18 Feb 2016 08:25:36 -0800
MIME-Version: 1.0
Content-Type: multipart/alternative;boundary="----=_NextPart_hTUHy..uLF3qVgnLqYEaQKd21"

The different casing in the headers seems to make no difference. In both cases, only the address listed in the To: field receives the mail. Those in the Cc: don't.

Questions

  1. Any ideas on what I might be missing here?

  2. Should I even be using mailfactory? (Recently noticed some repos w/ their last commit 8yrs+ ago...)

  3. If this is deprecated/obsoleted, what is its replacement and where can I find it + docs/examples? (I've not found meaningful docs for mailfactory...)

  4. Am I using Net::SMTP incorrectly or just missing something there?

I'm been browsing a few other libs, and I saw mail and Pony suggested in a different SO post, though I'm not sure if I'm just going to run into the same problem...

Help appreciated.

Other References

I already went through other SO questions, including, but not limited to those below. I tried some of their suggestions, but they didn't seem to work for me.

  1. Ruby Net::SMTP - Send email with bcc: recipients

  2. Email subject not correctly assigned with Ruby net/smtp

code_dredd
  • 5,915
  • 1
  • 25
  • 53

2 Answers2

0

You'd be better off using "actionmailer" or the "mail" gems. Both have good documentation.

https://github.com/rails/rails/tree/master/actionmailer

https://github.com/mikel/mail

Stephen Grimes
  • 398
  • 1
  • 7
0

I ended up dropping the use of mailfactory to try mail instead, but I hit an issue not covered in the documentation. The doc-based example below:

Mail.defaults do
  delivery_method :smtp, address: 'smtp.domain.com', port: 25
end

fails with Net::SMTPServerBusy exception:

/usr/lib/ruby/2.1.0/net/smtp.rb:957:in `check_response': 450 4.7.1 <localhost.localdomain>: Helo command rejected: Service temporarily unavailable (Net::SMTPServerBusy)

For some reason, it insists in using the localhost instead of the specified server specified by the address key. This looks like a bug in mail (2.6.3) to me... though I might be missing something.

Instead, I had to add the :domain => 'domain.com' pair to get around the problem, as shown below:

options = {
  :address => 'smtp.domain.com',
  :port    => 25,
  :domain  => 'domain.com'  # <<-- required
}

Mail.defaults do
  delivery_method :smtp, options
end

This this SO post was helpful in figuring this out.


EDIT-1: Although this did work in the testing environment, the production environment still has the problem. I will update this post when this is fully solved.

EDIT-2: It turns out that the SMTP server was causing a Net::SMTPFatalError exception with the error message Relay access denied. I'm not sure why that was happening, but it appears to be a side-effect of how the IT Dept. has configured the servers.

Instead, to solve the Net::SMTPFatalError I had to use a different internal SMTP server that had been configured to allow relaying emails to internal addresses.

After running the program in production yesterday, the previously missing emails started to show up as expected.

code_dredd
  • 5,915
  • 1
  • 25
  • 53