GithubHelp home page GithubHelp logo

Comments (4)

jwoertink avatar jwoertink commented on June 26, 2024 1

I like that. It makes sense. I think I just need some sort of mechanism that tells the Email that when we call deliver, don't actually do it. So I guess the skip_email method would be the thing that sets the flag.

I'm thinking something like this:

abstract class Carbon::Email
  property? deliverable : Bool = true

  def skip_sending_email
    self.deliverable = false
  end
end

So the before/after hooks would all be empty similar to how they work in Avram. It would be up to you to decide what logic happens. The difference is Avram has add_error() and valid? which will short circuit the saving. In this case, we don't have that.

carbon/src/carbon/email.cr

Lines 124 to 126 in 6cda3dd

def deliver
settings.adapter.deliver_now(self)
end

This then becomes more like

def deliver
  before_send

  if deliverable?
    response = settings.adapter.deliver_now(self)
    after_send(response)
  end
end

Does that sound good?

from carbon.

jwoertink avatar jwoertink commented on June 26, 2024

Doing this would actually solve the case for #61

class NotifierEmail < BaseEmail
  def initialize(@recipient : Carbon::Emailable)
  end

  before_send do
    # this would be up to you
    unless @recipient.wants_to_get_marketing_emails?
      # not sure about this... 
      skip_sending
    end
  end

  after_send do |delivery_response|
    # if this runs, the delivery_response would
    # be the return value of the deliver_now adapter method
  end

  to @recipient
  subject "Info for you"
  templates text, html
end

I also wonder if this would fit better in the Deliver Later strategy 🤔 It might be something you could do now possibly?

class CustomHookDeliverStrategy < Carbon::DeliverLaterStrategy

  def run(email : Carbon::Email, &block)
    before_send(email)
    response = block.call
    after_send(email, response)
  end

  def before_send(email)
    # custom logic
  end

  def after_send(email, response)
    # custom logic
  end
end

BaseEmail.configure do |settings|
  settings.deliver_later_strategy = CustomHookDeliverStrategy.new
end

The downsides to doing that path would be that you'd have to ALWAYS call deliver_later to get the callbacks. Calling deliver would skip those (maybe built-in escape hatch?). The next thing is where the logic for this all goes... On the one hand you could do it like this and have access to the email being sent, or you could move it in to all of the emails and call something like email.before_send instead of before_send(email). But if you do put the logic here, you can't guarantee that the recipient of the email is always the same type of object. For example, you may have a User and Admin as two separate models. Trying to short circuit the email here could get a little hairy.

from carbon.

jwoertink avatar jwoertink commented on June 26, 2024

It also seems that this could coincide with #43 Where the idea is that you could subscribe to before email sending events, or after sending email events to do whatever it is you need (maybe save to Breeze?)

from carbon.

robacarp avatar robacarp commented on June 26, 2024

At the strategy layer, in order to solve #61 you'd need to be able to tag an email with a type (marketing, password, transactional) and then short circuit it in there. I don't think that's a great way to solve it. I can see that there would be some benefits to having a before/after hook at the strategy layer but I don't think it's a good fit for filtering out unwanted emails. It feels like a place to hang framework level concerns instead.

Adding a before hook to the Email base class seems like it'd be really powerful. Eg:

# include into any email which can be opted-out of
module EmailOptOutHandler
  macro included
    before_send do
      unless @recepient.opt_in_email_types.includes? @type
        skip_email
      end
    end
  end
end

from carbon.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.