Class: Inquirex::SendEmail
- Inherits:
-
Object
- Object
- Inquirex::SendEmail
- Defined in:
- lib/inquirex/send_email.rb
Overview
A declarative email built from the collected answers, declared at flow
level with the DSL verb send_email. This is the only server-side
completion declaration the core gem carries — anything richer (webhooks,
CRM pushes, custom code) belongs to the host application.
send_email if: not_empty(:email) do
to "{{email}}"
from "forms@agentica.group"
subject "Thanks {{name}} — we got your inquiry"
markdown_text <<~TEXT
Hi {{name}},
We received your answers and will reply within one business day.
{{answers_summary}}
TEXT
end
Nothing is ever delivered by this gem. A SendEmail is data: templated header fields plus one or more body templates, serialized into the definition JSON under "send_emails". The host application decides when (and whether) to render and deliver — either from the serialized fields directly, or via #to_mail, which builds a Mail::Message (the object ActionMailer wraps).
Scalar fields (to, from, cc, bcc, reply_to, subject) and the text / markdown_text bodies render {field} values verbatim; the html body HTML-escapes every interpolated value automatically. markdown_text is carried on the wire as markdown — the core gem never renders Markdown to HTML (no dependencies); hosts that want an HTML part render it themselves.
Bodies accept an inline template String or { file: "path" }, which is read once at definition time and inlined — a definition rehydrated from JSON never touches the filesystem.
The mail gem is a soft dependency, required only when #to_mail is called. Rails hosts always have it (ActionMailer depends on it).
Constant Summary collapse
- SCALAR_FIELDS =
Scalar header fields rendered verbatim via Template.render_text in #to_mail and #to_h.
%i[to from cc bcc reply_to subject].freeze
Instance Attribute Summary collapse
-
#bcc ⇒ String?
readonly
Optional address templates ({field} placeholders allowed).
-
#cc ⇒ String?
readonly
Optional address templates ({field} placeholders allowed).
-
#from ⇒ String?
readonly
Optional address templates ({field} placeholders allowed).
-
#headers ⇒ Hash{String => String}
readonly
Extra headers (values support {field}).
-
#html ⇒ String?
readonly
Body template, inlined at definition time when { file: } was given.
-
#markdown_text ⇒ String?
readonly
Body template, inlined at definition time when { file: } was given.
-
#reply_to ⇒ String?
readonly
Optional address templates ({field} placeholders allowed).
-
#rule ⇒ Rules::Base?
readonly
Gate — the email applies only when the rule is true.
-
#subject ⇒ String
readonly
Required recipient / subject templates ({field} placeholders allowed).
-
#text ⇒ String?
readonly
Body template, inlined at definition time when { file: } was given.
-
#to ⇒ String
readonly
Required recipient / subject templates ({field} placeholders allowed).
Class Method Summary collapse
Instance Method Summary collapse
-
#applicable?(answers_hash) ⇒ Boolean
Whether this email should be built for the given answers — true when no gate was declared or the gate rule evaluates to true.
-
#initialize(to: nil, subject: nil, from: nil, cc: nil, bcc: nil, reply_to: nil, text: nil, markdown_text: nil, html: nil, headers: {}, rule: nil) ⇒ SendEmail
constructor
A new instance of SendEmail.
-
#to_h ⇒ Hash
Wire format, same shape .from_h accepts.
-
#to_mail(answers) ⇒ Mail::Message
Builds a Mail::Message from the templates and the given answers.
Constructor Details
#initialize(to: nil, subject: nil, from: nil, cc: nil, bcc: nil, reply_to: nil, text: nil, markdown_text: nil, html: nil, headers: {}, rule: nil) ⇒ SendEmail
Returns a new instance of SendEmail.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/inquirex/send_email.rb', line 70 def initialize(to: nil, subject: nil, from: nil, cc: nil, bcc: nil, reply_to: nil, text: nil, markdown_text: nil, html: nil, headers: {}, rule: nil) @to = to @from = from @cc = cc @bcc = bcc @reply_to = reply_to @subject = subject @text = resolve_body(text) @markdown_text = resolve_body(markdown_text) @html = resolve_body(html) @headers = headers.transform_keys(&:to_s).freeze @rule = rule validate! freeze end |
Instance Attribute Details
#bcc ⇒ String? (readonly)
Returns optional address templates ({field} placeholders allowed).
50 51 52 |
# File 'lib/inquirex/send_email.rb', line 50 def bcc @bcc end |
#cc ⇒ String? (readonly)
Returns optional address templates ({field} placeholders allowed).
50 51 52 |
# File 'lib/inquirex/send_email.rb', line 50 def cc @cc end |
#from ⇒ String? (readonly)
Returns optional address templates ({field} placeholders allowed).
50 51 52 |
# File 'lib/inquirex/send_email.rb', line 50 def from @from end |
#headers ⇒ Hash{String => String} (readonly)
Returns extra headers (values support {field}).
56 57 58 |
# File 'lib/inquirex/send_email.rb', line 56 def headers @headers end |
#html ⇒ String? (readonly)
Returns body template, inlined at definition time when { file: } was given.
53 54 55 |
# File 'lib/inquirex/send_email.rb', line 53 def html @html end |
#markdown_text ⇒ String? (readonly)
Returns body template, inlined at definition time when { file: } was given.
53 54 55 |
# File 'lib/inquirex/send_email.rb', line 53 def markdown_text @markdown_text end |
#reply_to ⇒ String? (readonly)
Returns optional address templates ({field} placeholders allowed).
50 51 52 |
# File 'lib/inquirex/send_email.rb', line 50 def reply_to @reply_to end |
#rule ⇒ Rules::Base? (readonly)
Returns gate — the email applies only when the rule is true.
59 60 61 |
# File 'lib/inquirex/send_email.rb', line 59 def rule @rule end |
#subject ⇒ String (readonly)
Returns required recipient / subject templates ({field} placeholders allowed).
47 48 49 |
# File 'lib/inquirex/send_email.rb', line 47 def subject @subject end |
#text ⇒ String? (readonly)
Returns body template, inlined at definition time when { file: } was given.
53 54 55 |
# File 'lib/inquirex/send_email.rb', line 53 def text @text end |
#to ⇒ String (readonly)
Returns required recipient / subject templates ({field} placeholders allowed).
47 48 49 |
# File 'lib/inquirex/send_email.rb', line 47 def to @to end |
Class Method Details
.from_h(hash) ⇒ SendEmail
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/inquirex/send_email.rb', line 133 def self.from_h(hash) fetch = ->(key) { hash[key.to_s] || hash[key.to_sym] } rule_data = fetch.call(:if) new( to: fetch.call(:to), from: fetch.call(:from), cc: fetch.call(:cc), bcc: fetch.call(:bcc), reply_to: fetch.call(:reply_to), subject: fetch.call(:subject), text: fetch.call(:text), markdown_text: fetch.call(:markdown_text), html: fetch.call(:html), headers: fetch.call(:headers) || {}, rule: rule_data ? Rules::Base.from_h(rule_data) : nil ) end |
Instance Method Details
#applicable?(answers_hash) ⇒ Boolean
Whether this email should be built for the given answers — true when no gate was declared or the gate rule evaluates to true.
92 93 94 |
# File 'lib/inquirex/send_email.rb', line 92 def applicable?(answers_hash) @rule.nil? || @rule.evaluate(answers_hash) end |
#to_h ⇒ Hash
Returns wire format, same shape .from_h accepts.
117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/inquirex/send_email.rb', line 117 def to_h hash = {} hash["if"] = @rule.to_h if @rule SCALAR_FIELDS.each do |field| value = public_send(field) hash[field.to_s] = value if value end hash["text"] = @text if @text hash["markdown_text"] = @markdown_text if @markdown_text hash["html"] = @html if @html hash["headers"] = @headers unless @headers.empty? hash end |
#to_mail(answers) ⇒ Mail::Message
Builds a Mail::Message from the templates and the given answers. Pure function — safe to call from a background job to rebuild messages from persisted answers. The text part is @text, falling back to @markdown_text rendered verbatim (Markdown reads fine as plain text); the html part is @html when present.
104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/inquirex/send_email.rb', line 104 def to_mail(answers) require_mail! mail = ::Mail.new SCALAR_FIELDS.each do |field| value = public_send(field) mail.public_send(:"#{field}=", Template.render_text(value, answers)) if value end @headers.each { |name, value| mail.header[name] = Template.render_text(value.to_s, answers) } attach_bodies(mail, answers) mail end |