Why does tmail stop my CGI script form working?


#1

I decided to try TMail for the back end of a new contact page on a
website of mine. Unfortunately, it doesn’t seem to want to work with
me.

If I don’t include a line like:
puts “Content-Type: text/html\n\n”

or like:
puts “Content-Type: text/plain\n\n”

. . . it fails with a 500 error in the browser.

If that line comes after this line:
require ‘tmail’

. . . I get the same 500 error.

If I put it before the require ‘tmail’ line, however, I get a blank page
with no error messages, but no email gets sent.

If I run the script from the shell (logged in on the server), it sends
email just fine, regardless of whether that puts line is before or after
the require ‘tmail’ line. Using print instead of puts doesn’t seem to
make any difference, either.

Even if I have the puts line before the require ‘tmail’ line, no puts
lines after the require line give me any output in the browser. If I
add
another puts line after the first, before the require line, it’ll print
whatever I tell it to in the browser, though.

So, basically, the script just seems to be broken from the moment I
require the TMail library, but it breaks “silently” so I don’t get any
errors – but everything up to that point seems to work just fine
(including other require statements, before or after the content type
line).

What am I doing wrong?


#2

On Nov 16, 2008, at 20:05 , Chad P. wrote:

So, basically, the script just seems to be broken from the moment I
require the TMail library, but it breaks “silently” so I don’t get any
errors – but everything up to that point seems to work just fine
(including other require statements, before or after the content type
line).

what does the web server’s error log say? I doubt it dies silently.
you’re prolly just not looking in the right spot.


#3

On Mon, Nov 17, 2008 at 01:45:05PM +0900, Chad P. wrote:

what does the web server’s error log say? I doubt it dies silently.
you’re prolly just not looking in the right spot.

I guess I should have been clearer:

It fails without any error that shows up in the browser. Since it’s
shared hosting, and I’m unable to even see an Apache log anywhere, I
figure I must not have direct access to the web server logs.

I’ve tried wrapping the require statement in some exception handling
code, too, and that doesn’t seem to give me anything useful either.

Whoops – I had a typo in my exception handling code. I’ve fixed it, so
it looks like this:

begin
  require 'tmail'
rescue Exception => e
  puts "#{e.class} : #{e}"
end

. . . and the output in the browser now looks like this:

LoadError : no such file to load -- tmail

. . . but, as I said before, it works from the shell, so I know tmail is
on the system and accessible.


#4

On Mon, Nov 17, 2008 at 01:16:25PM +0900, Ryan D. wrote:

you’re prolly just not looking in the right spot.
I guess I should have been clearer:

It fails without any error that shows up in the browser. Since it’s
shared hosting, and I’m unable to even see an Apache log anywhere, I
figure I must not have direct access to the web server logs.

I’ve tried wrapping the require statement in some exception handling
code, too, and that doesn’t seem to give me anything useful either.


#5

On Mon, Nov 17, 2008 at 02:23:24PM +0900, Jeremy McAnally wrote:

What user is the script running as? The environment may not be setup
properly and therefore unable to find gems etc.

It’s running as the same user both from the shell (where it works) and
the browser (where it doesn’t). Also, it doesn’t seem to have any
problems with other gems I require.


#6

What user is the script running as? The environment may not be setup
properly and therefore unable to find gems etc.

–Jeremy

On Sun, Nov 16, 2008 at 11:06 PM, Chad P. removed_email_address@domain.invalid
wrote:

code, too, and that doesn’t seem to give me anything useful either.
. . . and the output in the browser now looks like this:


http://jeremymcanally.com/
http://entp.com/
http://omgbloglol.com

My books:
http://manning.com/mcanally/
http://humblelittlerubybook.com/ (FREE!)


#7

On Nov 16, 2008, at 21:06 , Chad P. wrote:

begin
require ‘tmail’
rescue Exception => e
puts “#{e.class} : #{e}”
end

. . . and the output in the browser now looks like this:

LoadError : no such file to load – tmail

possibilities:

  1. multiple ruby installs, webserver is using something different.
  2. RUBYOPT
  3. private gems?

Try this:

% env -i $SHELL --norc
% ruby myscript.cgi < /dev/null

cause that is roughly all the web browser is gonna do.


#8

Unable to get tmail working properly on my shared hosting account, I
decided to take a whack at using the command line mail program instead
of tmail and net/smtp. I’d appreciate any commentary that might help me
fix this up, in case of bugs or security concerns. The end result looks
somewhat like this:

#!/usr/bin/env ruby
require 'rubygems'
require 'cgi'

cgi = CGI.new
print "Content-Type: text/html\n\n"

args = cgi.params

args.each_key do |k|
  args[k] = args[k].to_s.gsub(/"/, "''")
end

body_c = "

  name:  #{args['realname']}
  email: #{args['email']}
  tel.:  #{args['telephone']}

#{args['comments']}
"


sub_c =     "AL Contact Form: #{args['subject']}"
to_c =      'removed_email_address@domain.invalid'

`echo "#{body_c}" | mail -s '#{sub_c}' #{to_c}`

puts '<meta http-equiv="refresh" 

content=“0;URL=http://example.com/contact” />’

Obviously, “example.com” isn’t the real domain name, and “user” isn’t
the
actual user name.

I’m sure you’ll notice the quote-replacement code. Nothing else comes
to
mind that’d constitute a problematic character to send to the shell, but
if you know of any others I’d like to hear about it. I looked around
for
a string sanitizer appropriate to my needs here, but didn’t find
anything
in the standard library or core language, and if I start adding gems I’m
going to end up with the same problem I had trying to get tmail and
rmail
to work (yeah, I tried rmail too – same problem).


#9

Why not try mailfactory if you’re just sending e-mail? If it’s just
tmail screwing up. I thought perhaps you were parsing e-mail or
something.

–Jeremy

On Mon, Nov 17, 2008 at 3:49 AM, Chad P. removed_email_address@domain.invalid
wrote:

cgi = CGI.new
name: #{args[‘realname’]}
echo "#{body_c}" | mail -s '#{sub_c}' #{to_c}
in the standard library or core language, and if I start adding gems I’m
going to end up with the same problem I had trying to get tmail and rmail
to work (yeah, I tried rmail too – same problem).


Chad P. [ content licensed PDL: http://pdl.apotheon.org ]
Quoth Thomas McCauley: “The measure of a man’s real character is what he
would do if he knew he would never be found out.”


http://jeremymcanally.com/
http://entp.com/
http://omgbloglol.com

My books:
http://manning.com/mcanally/
http://humblelittlerubybook.com/ (FREE!)


#10

On Nov 17, 2008, at 11:38 AM, Chad P. wrote:

set of single quotes in the mail command into double quotes. The
line
in question should actually read:

echo "#{body_c}" | mail -s "#{sub_c}" #{to_c}

I would prefer to just avoid passing the body through the shell:

open(%Q{| mail -s “#{sub_c}” #{to_c}}, “w”) { |mail| mail << body_c }

You could use mail’s escapes to avoid passing the subject as well.
See the man page for details.

James Edward G. II


#11

On Tue, Nov 18, 2008 at 03:45:37AM +0900, James G. wrote:

Also . . . as someone pointed out to me off-list, I forgot to change a
set of single quotes in the mail command into double quotes. The
line
in question should actually read:

echo "#{body_c}" | mail -s "#{sub_c}" #{to_c}

I would prefer to just avoid passing the body through the shell:

open(%Q{| mail -s “#{sub_c}” #{to_c}}, “w”) { |mail| mail << body_c }

That’s an excellent point, and I wish I had thought of it. I took your
advice. The relevant code now looks like this:

sent = open( %Q{| mail -s "#{sub_c}" #{to_c} }, 'w' ) do |msg|
  msg << body_c
end

. . . and the sub_c variable just contains a non-interpolated string
with
nothing but letters and spaces in it. Since the to_c variable was
already just a non-interpolated string I defined within the script, I
think this means I’m no longer in need of input sanitizing. I think.

You could use mail’s escapes to avoid passing the subject as well.
See the man page for details.

I pored over the man page for a little while, and didn’t catch on to
what
you meant by this. The closest I found to it was the reference to the
~s
escape for the mail program, but I haven’t figured out yet what you
meant
should be done with it if that’s your point.

However . . . having a user-supplied string in the actual email subject
line isn’t really a critical necessity so, for the sake of moving
forward, I just made the subject line of sent emails static and
predefined in the script, then put the user-supplied subject string
within the body of the email the same way I did with the name and
telephone number fields.

If using a block rather than an echo command eliminates the need to
sanitize the text in the message body, it looks like the problem of
input
sanitizing is solved for now, and I really appreciate your help. Please
correct me if I’m wrong.

I’ll probably put some more time into puzzling over man mail at a
later
date to see if I can figure out what you meant about using mail’s
escapes
to avoid passing the subject to the shell. That would surely be good to
know for the future, even if it isn’t really critical to this particular
case.


#12

On Tue, Nov 18, 2008 at 01:20:16AM +0900, Jeremy McAnally wrote:

Why not try mailfactory if you’re just sending e-mail? If it’s just
tmail screwing up. I thought perhaps you were parsing e-mail or
something.

The problem actually appears to be one of something on the server being
misconfigured so that I cannot properly install and require gems.

Also . . . as someone pointed out to me off-list, I forgot to change a
set of single quotes in the mail command into double quotes. The line
in question should actually read:

`echo "#{body_c}" | mail -s "#{sub_c}" #{to_c}`

. . . rather than:

`echo "#{body_c}" | mail -s '#{sub_c}' #{to_c}`

#13

On Tue, Nov 18, 2008 at 05:05:32AM +0900, James G. wrote:

mail << body_c
mail.close_write
mail.read

end

Actually, I stuck the sent variable in there for diagnostic purposes and
just forgot to remove it before copying and pasting.

I’ve never used that feature myself, but I suspect you would use it
like this:

mail << “~s #{sub_c}\n#{body_c}”

I’m guessing though and could be wrong. Double check me there.

Thanks. I’ll look into that.


#14

On Nov 17, 2008, at 1:54 PM, Chad P. wrote:

being
I would prefer to just avoid passing the body through the shell:
end
Is sent meant to contain the output? If so, we should probably change
that code to:

sent = open(%Q{| mail -s"#{sub_c}" #{to_c} }, “r+”) do |mail|
mail << body_c
mail.close_write
mail.read
end

You could use mail’s escapes to avoid passing the subject as well.
See the man page for details.

I pored over the man page for a little while, and didn’t catch on to
what
you meant by this. The closest I found to it was the reference to
the ~s
escape for the mail program, but I haven’t figured out yet what you
meant
should be done with it if that’s your point.

I’ve never used that feature myself, but I suspect you would use it
like this:

mail << “~s #{sub_c}\n#{body_c}”

I’m guessing though and could be wrong. Double check me there.

James Edward G. II