dreamfactory/df-email
df-email adds an email service to DreamFactory, letting APIs and scripts send messages through configurable SMTP connections. It supports common email fields, attachments, and platform integration for transactional notifications and workflows.
df-ebook is not a general-purpose mailer — it is a DreamFactory service package. You only get value from it if you are running (or setting up) a DreamFactory instance and want email send/receive exposed as a managed REST endpoint, then calling that endpoint from your Laravel app or any other client. If you just want to send mail from a Laravel app, use laravel/mail — this package will only add weight and confusion.
Assumes DreamFactory 4.x (Laravel/Lumen-based, dreamfactory/df-core present).
Install into the DreamFactory instance (not your app):
composer require dreamfactory/df-email
DreamFactory packages advertise themselves through extra.dreamfactory in their composer.json, so provider discovery is automatic. After installing you still need to re-run the service seeding step for the instance (the df:setup/df:import-services flow documented in the DreamFactory admin guide) so the new email service types appear in the admin console.
Where to look first, in order:
composer.json → extra.dreamfactory.df-email (lists the service providers and the config keys). This is the fastest summary of what the package actually registers.src/Providers/ → the service providers, one per service type (typically an SMTP Email service and IMAP/POP3 read services).src/Services/ → the service classes themselves. The handler methods (send, list, get, etc.) are the real API surface.database/migrations/ and config/ → how service rows are seeded and which config keys each service type expects.First use case — send a transactional email through DreamFactory:
from address.email).curl -X POST 'https://df.example.com/api/v2/email' \
-H 'X-DreamFactory-API-Key: YOUR_KEY' \
-H 'Authorization: Bearer YOUR_SESSION_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"to": "[email protected]",
"subject": "Welcome",
"body": "Thanks for signing up."
}'
The exact path/verb for send varies by DreamFactory and df-email version — after registering the service, open /api/v2/api_docs in the same instance and use the generated Swagger entry as the source of truth rather than guessing.
Treat it as an HTTP dependency, not a Composer dependency. From a Laravel app, wrap calls behind a small client:
class DreamFactoryMailer
{
public function __construct(private Http $http, private string $baseUrl, private string $apiKey) {}
public function send(string $to, string $subject, string $body): array
{
return $this->http
->withHeaders(['X-DreamFactory-API-Key' => $this->apiKey])
->withToken(config('services.dreamfactory.session_token'))
->post("{$this->baseUrl}/api/v2/email", compact('to', 'subject', 'body'))
->throw()
->json();
}
}
Swap this behind Laravel's Mail abstraction if you want a drop-in (implement Mailer or use a custom transport), so application code doesn't care whether mail flows through SMTP directly or through DreamFactory.
Service-per-environment. df-email services are configured and stored as database rows, so you can register multiple services against one instance — e.g. email-transactional, email-marketing, email-support — each with its own SMTP credentials. This is the main reason to use the package at all: credentials are managed centrally in the DreamFactory admin console rather than shipped in .env files across apps.
Read side (IMAP/POP3) as a data feed. The read services behave like other DreamFactory data services: you can GET a mailbox and pipe the response into a Laravel job for parsing, storing to messages tables, and triggering notifications. Do the polling in a queued job, not a request cycle — mailboxes are slow to enumerate.
Use DreamFactory roles for authorisation. Rather than checking "can this user send mail?" in your app, attach an API role to the service that restricts which endpoints a token can hit. Then issue scoped tokens per feature (e.g. a token that can POST to email but not GET the inbox).
Keep a thin Laravel service provider binding DreamFactoryMailer as a singleton so you can fake it in tests:
$this->app->singleton(DreamFactoryMailer::class, fn () => new DreamFactoryMailer(
app(Http::class),
config('services.dreamfactory.url'),
config('services.dreamfactory.key'),
));
Version pinning matters. DreamFactory's ecosystem moves together — df-core, df-email, and the framework version must be compatible. In the host app's composer.json, pin dreamfactory/df-email to a specific minor and upgrade it only alongside a DreamFactory upgrade. There's no ^ range you should trust by default.
It is not installable into a plain Laravel app. df-email assumes dreamfactory/df-core and the DreamFactory service plumbing (Service, ServiceProvider base classes, service table migrations). Composer will install it, but nothing will work standalone. If your goal is "Laravel sends email", stop here.
imap and openssl PHP extensions. The read services need imap (or an equivalent library) compiled into the PHP CLI that runs DreamFactory. SMTP-only usage needs openssl for tls/ssl encryption. Missing extensions surface as opaque connection failures, not clear errors — verify with php -m first.
Port and encryption mismatch is the #1 support ticket. 465 → ssl, 587 → tls (STARTTLS), 25 → usually tls or none. If you get "connection refused" or timeouts, the port is wrong or the host is blocking it; if you get "authentication failed", the encryption/port combination is wrong or the credential needs an app password (Gmail, M365, etc.).
from address restrictions. Many SMTP providers (SES, SendGrid, M365) reject sends where the from address isn't a verified sender/domain. The error usually comes back as a 500 from DreamFactory, not a 4xx, because the SMTP server returned it after the API accepted the request. Check the DreamFactory log (storage/logs/) for the underlying SMTP response.
Config is database-backed, not .env. Editing config/ or .env on the server will not change an existing service's SMTP settings — you must edit the service in the admin console, or re-seed. This trips people up after they've moved from local DreamFactory to production: the row still holds the old credentials. Keep credentials in your secrets manager and apply them via the admin API, not by hand.
Re-seeds can wipe custom service rows. Running the DreamFactory setup/import command after a df-email upgrade can reset the service definitions. Export your email service configs before upgrading and diff afterwards.
Authentication is two-layer. You need the X-DreamFactory-API-Key and a valid session/JWT, unless the service role is explicitly public. Debugging 401s: try the same call in /api/v2/api_docs (which carries your admin session) — if it works there but not from your app, the app token is the problem, not the service.
Extension points. The clean customisation path is to subclass the package's service provider/class in your own package and register a new service type, rather than editing vendor/. The provider's register() / boot() methods and the config array in extra.dreamfactory are the documented seams. For simple tweaks — default from-address, subject prefix — do it in your calling client, not in the package.
Low activity warning. Two stars, zero dependents, and an auto-generated release schedule mean little community support. Budget time to read src/ when something fails; expect to debug DreamFactory itself as much as this package. For anything send-only and modest in volume, bypassing it and using laravel/mail plus a direct SMTP provider is materially less risky. Use df-email when you specifically want email credentials and access control centralised inside an existing DreamFactory deployment.
How can I help you explore Laravel packages today?