benecaster_send_email()
benecaster_send_email( int $user_id, string $type, string $subject, string $template, array $context = [] ): int
Sends one Benecaster email to a WordPress user through the full dispatch pipeline. This is the supported way for an add-on to perform a send — a hook cannot do it, because benecaster_before_email_send lets you react to a send already under way and cannot be invoked to start one.
Registering a type does not make it send. benecaster_managed_email_types is a descriptive catalogue that makes a type discoverable and editable in the Email Editor; this function is what dispatches one. The two are separate steps and both are needed.
Everything the internal path does, this does: the should_send gate (and therefore unsubscribe suppression), merge-tag assembly, template resolution, subscriber-locale selection, the subject/body/from/header filters, and the before/after send actions. It is a pass-through, not a reimplementation.
Parameters
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
user_id |
int |
— | Yes | Recipient WordPress user ID. Not an email address — see the notes. |
type |
string |
— | Yes | Email type slug, e.g. welcome. Register it with benecaster_managed_email_types first so podcasters can find and edit it. |
subject |
string |
— | Yes | Subject line. Merge tags are replaced. |
template |
string |
— | Yes | Template name resolved by the renderer. |
context |
array |
[] |
No | Merge-tag context. A show_id key doubles as the send's show context — pass it whenever you have one. |
Return Value
Type:
int
The benecaster_email_queue row ID, or 0 when a filter suppressed the send, when the user has no address, or when the send failed. It is not a delivery result — the queue sends later, on the benecaster_process_email_queue cron pass.
Example
$queue_id = benecaster_send_email(
$user_id,
'my_episode_notification',
sprintf( __( 'New episode: %s', 'my-addon' ), get_the_title( $episode_id ) ),
'my-addon/episode-notification',
[
'show_id' => $show_id,
'episode_title' => get_the_title( $episode_id ),
'episode_url' => get_permalink( $episode_id ),
]
);
// 0 means suppressed or failed — most often an opt-out, which is not an
// error and must not be retried.
if ( 0 === $queue_id ) {
return;
}
Notes
Do not resolve EmailManager from the container to do this. That was the only route before this function existed, and it made an internal class part of the published surface. The class is not stable; this function is.
Pass show_id in $context whenever you have it. Unsubscribe enforcement needs both the user and the show — omit the show and a subscriber who opted out of that show still receives the mail.
$subject and $template are caller-supplied on purpose. The type registry carries neither, so there is nothing to look them up in; every core call site hardcodes its own pair and so must yours. $context is last in the signature so that if those two ever move into the registry, the signature can collapse to ( $user_id, $type, $context ) without reordering anything.
$user_id is a WordPress user ID, not an email address, and that is deliberate. The queue stores recipient_user_id and resolves the address from it; a row for an address with no user account enqueues with user_id = 0 and is then failed permanently by the processor. Accepting an arbitrary address would promise delivery the queue cannot make. Resolve an address first with benecaster_get_user_id_by_subscriber_email().
A 0 return is the only signal a caller gets that a filter suppressed the send, which is why this returns an int rather than a bool. Treat it as do not retry, not as a transient failure — the most common cause is an opt-out, which is not an error.
For one-off mail with no registered type behind it, use benecaster_mail() instead.
Need this built rather than just documented? See our services →