Outbound Campaigns
Drip a prospect campaign through a sender pool with mailbox ramping, daily caps, threaded follow-ups, and auto-pause on reply.
Sender pool
Health, capacity, and per-mailbox spacing update as outcomes run.
Enroll prospects to see the outbound outcome grid.
Sequence steps
Follow each step as it queues up, sends, and completes.
Sequence code
tenant_key = "demo"
sender_attrs = [
{"Goodway Alex", "alex@goodway.dev"},
{"Goodway Jamie", "jamie@goodway.dev"},
{"Goodway Sam", "sam@goodway.dev"}
]
senders =
Enum.map(sender_attrs, fn {name, email} ->
{:ok, adapter} =
DripDrop.create_channel_adapter(%{
tenant_key: tenant_key,
name: name,
channel: "email",
provider: "local",
is_default: false,
credentials: %{"from" => "#{name} <#{email}>"},
daily_cap: 45,
min_gap_seconds: 2
})
adapter
end)
{:ok, pool} =
DripDrop.create_adapter_pool(%{
tenant_key: tenant_key,
name: "outbound_pool",
on_pin_unavailable: :reassign
})
Enum.each(senders, fn adapter ->
{:ok, _member} =
DripDrop.add_pool_member(pool, %{
tenant_key: tenant_key,
adapter_id: adapter.id,
class: "mailbox",
weight: 1,
active: true
})
end)
{:ok, sequence} =
DripDrop.create_sequence(%{
tenant_key: tenant_key,
name: "Goodway Elixir consulting outbound",
key: "outbound-campaigns",
description: "Outbound campaign for Goodway Elixir software development consulting.",
active: true,
metadata: %{"demo" => true}
})
{:ok, version} =
DripDrop.create_sequence_version(sequence.id, %{
version: 1,
name: "Goodway consulting campaign",
mode: :outbound,
config: %{"pool_id" => pool.id}
})
{:ok, intro} =
DripDrop.create_step(version.id, %{
name: "Initial consulting email",
key: "consulting-intro",
position: 1,
channel: "email",
timing: %{type: "immediate"},
template_type: "inline",
template_content: %{
"subject" => "Phoenix and LiveView help for {{ company }}",
"text" =>
"Hi {{ first_name }}, Goodway helps teams stabilize Phoenix apps, clean up LiveView bottlenecks, and ship Elixir features without slowing the product team down. Is that relevant for {{ company }} this quarter?",
"html" =>
"<p>Hi {{ first_name }}, Goodway helps teams stabilize Phoenix apps, clean up LiveView bottlenecks, and ship Elixir features without slowing the product team down. Is that relevant for {{ company }} this quarter?</p>"
},
config: %{"quiet_hours" => false, "spintax_seed" => "goodway-elixir-intro"}
})
{:ok, follow_up} =
DripDrop.create_step(version.id, %{
name: "Threaded follow-up",
key: "consulting-follow-up",
position: 2,
channel: "email",
timing: %{type: "delay", delay_amount: 10, delay_unit: "seconds"},
template_type: "inline",
template_content: %{
"subject" => "Re: Phoenix and LiveView help for {{ company }}",
"text" =>
"A lot of Phoenix teams call us when LiveView screens get state-heavy, background jobs hide production issues, or releases need someone senior to pair with the internal team. Worth comparing notes?",
"html" =>
"<p>A lot of Phoenix teams call us when LiveView screens get state-heavy, background jobs hide production issues, or releases need someone senior to pair with the internal team. Worth comparing notes?</p>"
},
config: %{"quiet_hours" => false, "reply_behavior" => "pause_enrollment"}
})
{:ok, final_bump} =
DripDrop.create_step(version.id, %{
name: "Final bump",
key: "consulting-final-bump",
position: 3,
channel: "email",
timing: %{type: "delay", delay_amount: 12, delay_unit: "seconds"},
template_type: "inline",
template_content: %{
"subject" => "Re: Phoenix and LiveView help for {{ company }}",
"text" =>
"Last note from me. If Phoenix, LiveView, or Elixir reliability work sits with someone else at {{ company }}, who is the better person to ask?",
"html" =>
"<p>Last note from me. If Phoenix, LiveView, or Elixir reliability work sits with someone else at {{ company }}, who is the better person to ask?</p>"
},
config: %{"quiet_hours" => false, "reply_behavior" => "pause_enrollment"}
})
for {from_step, to_step} <- [
{intro, follow_up},
{follow_up, final_bump},
{final_bump, nil}
] do
{:ok, _transition} =
DripDrop.create_step_transition(version.id, %{
from_step_id: from_step.id,
to_step_id: to_step && to_step.id,
condition_mode: "always",
priority: 1
})
end
{:ok, _validated} = DripDrop.validate_sequence_version(version.id)
{:ok, _activated} = DripDrop.activate_sequence_version(version.id)
for {first_name, company, email} <- [
{"Mia", "Northstar SaaS", "mia@northstar.example"},
{"Jordan", "Atlas Metrics", "jordan@atlas.example"},
{"Priya", "SignalOps", "priya@signalops.example"},
{"Eli", "Runway Data", "eli@runway.example"},
{"Nora", "StackPilot", "nora@stackpilot.example"},
{"Theo", "OpsCanvas", "theo@opscanvas.example"},
{"Avery", "MetricForge", "avery@metricforge.example"},
{"Quinn", "LaunchGrid", "quinn@launchgrid.example"}
] do
DripDrop.enroll(%{
sequence_id: sequence.id,
subscriber_type: "prospect",
subscriber_id: "goodway-prospect-#{System.unique_integer([:positive])}",
tenant_key: tenant_key,
data: %{
"first_name" => first_name,
"company" => company,
"email" => email,
"interest" => "Elixir software development consulting"
}
})
end
Sequence messages
Outbound emails appear here as each campaign step is sent.
Sequence logs
# Live DripDrop events will stream here after dispatch starts.