I'm new to Ruby and wondering why I am getting an error in this situation using the 'mail' gem in a simple Sinatra app:
post "/email/send" do
@recipient = params[:email]
Mail.deliver do
to @recipient # throws error as this is undefined
from 'server@domain.com'
subject 'testing sendmail'
body 'testing sendmail'
end
erb :email_sent
end
This however works fine:
post "/email/send" do
Mail.deliver do
to 'me@domain.com'
from 'server@domain.com'
subject 'testing sendmail'
body 'testing sendmail'
end
erb :email_sent
end
I suspect this is something to do with block scope and my misunderstanding of it.
As Julik says,
Mail#delivery
executes your block using#instance_exec
, which simply changesself
while running a block (you wouldn't be able to call methods#to
and#from
inside the block otherwise).What you really can do here is to use a fact that blocks are closures. Which means that it "remembers" all the local variables around it.
Again, briefly:
self
#instance_exec
changes theself
;self
and are remembered by blocks because blocks are closures.I think it's because the Mail gem uses
instance_exec
under the hood.instance_exec
uses instance variables from the object it's being called on and not from the caller. What I'd do is find a method in the Mail gem that does not use instance tricks but passes an explicit configuration object to the block, and proceed from there. Spares a few gray hairs.If you'll read through the docs for
Mail
further you'll find a nice alternate solution that will work. Rather than use:you can use Mail's
new()
method, passing in parameters, and ignore the block:or the alternate hash element definitions:
In pry, or irb you'd see:
The
new
method has several variations you can use. This is from the docs also, and might work better:followed by
mail.deliver!
.Also note, in the previous example, that there are multiple ways to access the various headers in the message envelope. It's a flexible gem that seems to be well thought out and nicely follows the Ruby way.