Overriding #send_reset_password_email function

70 views
Skip to first unread message

Laurent Guinotte

unread,
Apr 2, 2021, 10:00:39 AM4/2/21
to Rodauth
Hi,

I'm trying to integrate Rodauth to a simple Roda/Sequel app, and it's been great so far.

I have a question about the features that requires sending email, and I will concentrate on the Reset Password feature for brevity.

Using the Mail gem, everything works flawlessly in development and in tests. For production, I use Sendrgid.

I've managed to override the `#send_reset_password_email` auth method and to call a method on a custom helper module inside the block. It works, but I'm not sure if I'm doing it the right way.

My question is how to properly access values such as `email_from` and `email_to`, and basically, all other values that are useful for composing email.

Here is my simplified code :

```ruby
# app.rb
class App < Roda
  plugin :environments
 
  include MailHelpers if App.production?

  plugin :rodauth do
    enable :login, :logout, :reset_password  # and other features omitted...
    require_mail? false if App.production?
    send_reset_password_email { MailHelpers.send_reset_password_email(self) } if App.production?
    
    # and other configuration stuffs
    # ...
  end
end

# mail_helpers.rb
module MailHelpers
  include SendGrid

  def self.send_reset_password_email(rodauth)
    from = SendGrid::Email.new(email: rodauth.send(:email_from))  # private method call
    to = SendGrid::Email.new(email: rodauth.account[:email])
    subject = "My App - Password Reset Link"
    content = SendGrid::Content.new(type: 'text/html', value: rodauth.scope.render("mails/reset-password-email"))
    mail = SendGrid::Mail.new(from, subject, to, content)
    
    # code to actually send the email goes here
  end
end
```

In the `send_reset_password_email` block, I have passed `self` to the `MailHelpers#send_reset_password_email` instance method. If my understanding is correct `self` is here the `Rodauth::Auth` instance related to the request, the same object referenced by the `rodauth` method inside the routing tree.

What makes me uncomfortable is the call to the private method `email_from` within the module method.

I've read the Rodauth Internals Guide, and it helped, but I guess I'm missing something.

I could hard code the `from` email address in the `MailHelpers` module, but I'm not sure it's the way to go either.

Am I missing something about Rodauth / Roda, or is there another better approach that I don't see ?

Thanks a lot for these great libraries.

Laurent

Jeremy Evans

unread,
Apr 2, 2021, 10:53:12 AM4/2/21
to rod...@googlegroups.com
If you just care about overriding how email is delivered, using the Rodauth send_email configuration method is what you want to use.  Other things such as the subject you can configure via reset_password_email_subject or some such.

Another alternative is to leave Rodauth alone, and just add a sendgrid delivery method to the mail gem, and configure the mail gem to use it.

Thanks,
Jeremy

Laurent Guinotte

unread,
Apr 4, 2021, 4:59:46 AM4/4/21
to Rodauth
Hi Jeremy,

Thanks a lot for your help, I'll definitely try these solutions !

Laurent

Laurent Guinotte

unread,
Apr 9, 2021, 10:45:13 AM4/9/21
to Rodauth
Hi Jeremy and future readers,

I'm posting the code I wrote following Jeremy's advice, in case it would be helpful for others.


```ruby
# app.rb

require_relative 'helpers/mail_helpers'

class App < Roda
   plugin :rodauth do
     enable :login, :logout, :reset_password  # and other features omitted for brevity...
    
    # Email Base
    send_email { |mail| MailHelpers.send_email_with_sendgird(mail) } if ENV['RACK_ENV'] == "production"

    
    # and other configuration stuffs
    # ...
  end
end

# helpers/mail_helpers.rb

module MailHelpers
  include SendGrid

      # IMPORTANT : It seems that the local variable 'mail' must be named 'mail' in order
    # for Sendgrid to process the request correctly
    def self.send_mail_with_sendgrid(original_mail)
      from = SendGrid::Email.new(email: original_mail.from[0])
      to = SendGrid::Email.new(email: original_mail.to[0])
      subject = original_mail.subject
      content = SendGrid::Content.new(type: 'text/html', value: original_mail.body.raw_source)

      mail = SendGrid::Mail.new(from, subject, to, content)
      sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
      response = sg.client.mail._('send').post(request_body: mail.to_json)
    end
end
```

Cheers,

Laurent
Reply all
Reply to author
Forward
0 new messages