How to Send Emails from Angular (2026 Guide)

Angular runs in the browser. Like React, you can't send emails directly from the client. You call a backend API that holds your API key and sends the email server-side.
This guide covers the Angular side (services, forms, HttpClient) and the minimal backend needed.
The Pattern
Angular Form → HttpClient.post("/api/send-email") → Your Backend → Email Provider
Email Service
// src/app/services/email.service.ts
import { Injectable, inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
interface SendEmailRequest {
email: string;
message: string;
}
@Injectable({ providedIn: "root" })
export class EmailService {
private http = inject(HttpClient);
sendContactEmail(data: SendEmailRequest) {
return this.http.post<{ sent: boolean }>("/api/send-email", data);
}
sendWelcomeEmail(email: string, name: string) {
return this.http.post<{ jobId: string }>("/api/send-welcome", { email, name });
}
}Contact Form Component
// src/app/components/contact-form.component.ts
import { Component, inject } from "@angular/core";
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
import { EmailService } from "../services/email.service";
@Component({
selector: "app-contact-form",
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="email" type="email" placeholder="Your email" />
<textarea formControlName="message" placeholder="Message"></textarea>
<button type="submit" [disabled]="sending">
{{ sending ? "Sending..." : "Send" }}
</button>
@if (status === "sent") {
<p style="color: green">Message sent!</p>
}
@if (status === "error") {
<p style="color: red">Failed to send. Try again.</p>
}
</form>
`,
})
export class ContactFormComponent {
private emailService = inject(EmailService);
private fb = inject(FormBuilder);
form = this.fb.group({
email: ["", [Validators.required, Validators.email]],
message: ["", Validators.required],
});
sending = false;
status: "idle" | "sent" | "error" = "idle";
onSubmit() {
if (this.form.invalid) return;
this.sending = true;
this.status = "idle";
this.emailService
.sendContactEmail(this.form.value as { email: string; message: string })
.subscribe({
next: () => {
this.status = "sent";
this.sending = false;
this.form.reset();
},
error: () => {
this.status = "error";
this.sending = false;
},
});
}
}Backend API
import express from "express";
import Sequenzy from "sequenzy";
const app = express();
const sequenzy = new Sequenzy();
app.use(express.json());
app.post("/api/send-email", async (req, res) => {
const { email, message } = req.body;
if (!email || !message) {
return res.status(400).json({ error: "email and message required" });
}
try {
await sequenzy.transactional.send({
to: "you@yourcompany.com",
subject: `Contact from ${email}`,
body: `<p><strong>From:</strong> ${email}</p><p>${message}</p>`,
});
res.json({ sent: true });
} catch {
res.status(500).json({ error: "Failed to send" });
}
});
app.listen(3000);import express from "express";
import { Resend } from "resend";
const app = express();
const resend = new Resend(process.env.RESEND_API_KEY);
app.use(express.json());
app.post("/api/send-email", async (req, res) => {
const { email, message } = req.body;
if (!email || !message) {
return res.status(400).json({ error: "email and message required" });
}
const { error } = await resend.emails.send({
from: "Contact <noreply@yourdomain.com>",
to: "you@yourcompany.com",
subject: `Contact from ${email}`,
html: `<p><strong>From:</strong> ${email}</p><p>${message}</p>`,
});
if (error) return res.status(500).json({ error: "Failed to send" });
res.json({ sent: true });
});
app.listen(3000);import express from "express";
import sgMail from "@sendgrid/mail";
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
const app = express();
app.use(express.json());
app.post("/api/send-email", async (req, res) => {
const { email, message } = req.body;
if (!email || !message) {
return res.status(400).json({ error: "email and message required" });
}
try {
await sgMail.send({
to: "you@yourcompany.com",
from: "noreply@yourdomain.com",
subject: `Contact from ${email}`,
html: `<p><strong>From:</strong> ${email}</p><p>${message}</p>`,
});
res.json({ sent: true });
} catch {
res.status(500).json({ error: "Failed to send" });
}
});
app.listen(3000);Proxy in Development
Add a proxy to angular.json so Angular dev server forwards API requests:
// proxy.conf.json
{
"/api": {
"target": "http://localhost:3000",
"secure": false
}
}ng serve --proxy-config proxy.conf.jsonGoing to Production
1. Never Expose API Keys
Keep API keys on the server. Never put them in environment.ts.
2. Use Angular SSR
With Angular SSR, you can make email API calls directly in server-side code without a separate backend.
3. Verify Your Domain
Add SPF, DKIM, DMARC DNS records.
Beyond Transactional
Sequenzy handles transactional sends, marketing campaigns, automated sequences, and subscriber management from one API. Native Stripe integration for SaaS.
Wrapping Up
- Email service with HttpClient for API calls
- Reactive forms with validation and loading states
- Backend API to keep keys secure
- Dev proxy for local development
Pick your provider, build the backend, and connect your Angular forms.