diff --git a/coderd/autobuild/lifecycle_executor.go b/coderd/autobuild/lifecycle_executor.go
index 082ee0feedfcf..10692f91ff1c8 100644
--- a/coderd/autobuild/lifecycle_executor.go
+++ b/coderd/autobuild/lifecycle_executor.go
@@ -19,7 +19,6 @@ import (
 	"github.com/coder/coder/v2/coderd/database/dbtime"
 	"github.com/coder/coder/v2/coderd/database/provisionerjobs"
 	"github.com/coder/coder/v2/coderd/database/pubsub"
-	"github.com/coder/coder/v2/coderd/dormancy"
 	"github.com/coder/coder/v2/coderd/notifications"
 	"github.com/coder/coder/v2/coderd/schedule"
 	"github.com/coder/coder/v2/coderd/wsbuilder"
@@ -145,10 +144,11 @@ func (e *Executor) runOnce(t time.Time) Stats {
 				var (
 					job                   *database.ProvisionerJob
 					auditLog              *auditParams
-					dormantNotification   *dormancy.WorkspaceDormantNotification
+					shouldNotifyDormancy  bool
 					nextBuild             *database.WorkspaceBuild
 					activeTemplateVersion database.TemplateVersion
 					ws                    database.Workspace
+					tmpl                  database.Template
 					didAutoUpdate         bool
 				)
 				err := e.db.InTx(func(tx database.Store) error {
@@ -182,17 +182,17 @@ func (e *Executor) runOnce(t time.Time) Stats {
 						return xerrors.Errorf("get template scheduling options: %w", err)
 					}
 
-					template, err := tx.GetTemplateByID(e.ctx, ws.TemplateID)
+					tmpl, err = tx.GetTemplateByID(e.ctx, ws.TemplateID)
 					if err != nil {
 						return xerrors.Errorf("get template by ID: %w", err)
 					}
 
-					activeTemplateVersion, err = tx.GetTemplateVersionByID(e.ctx, template.ActiveVersionID)
+					activeTemplateVersion, err = tx.GetTemplateVersionByID(e.ctx, tmpl.ActiveVersionID)
 					if err != nil {
 						return xerrors.Errorf("get active template version by ID: %w", err)
 					}
 
-					accessControl := (*(e.accessControlStore.Load())).GetTemplateAccessControl(template)
+					accessControl := (*(e.accessControlStore.Load())).GetTemplateAccessControl(tmpl)
 
 					nextTransition, reason, err := getNextTransition(user, ws, latestBuild, latestJob, templateSchedule, currentTick)
 					if err != nil {
@@ -215,7 +215,7 @@ func (e *Executor) runOnce(t time.Time) Stats {
 							log.Debug(e.ctx, "autostarting with active version")
 							builder = builder.ActiveVersion()
 
-							if latestBuild.TemplateVersionID != template.ActiveVersionID {
+							if latestBuild.TemplateVersionID != tmpl.ActiveVersionID {
 								// control flag to know if the workspace was auto-updated,
 								// so the lifecycle executor can notify the user
 								didAutoUpdate = true
@@ -248,12 +248,7 @@ func (e *Executor) runOnce(t time.Time) Stats {
 							return xerrors.Errorf("update workspace dormant deleting at: %w", err)
 						}
 
-						dormantNotification = &dormancy.WorkspaceDormantNotification{
-							Workspace: ws,
-							Initiator: "autobuild",
-							Reason:    "breached the template's threshold for inactivity",
-							CreatedBy: "lifecycleexecutor",
-						}
+						shouldNotifyDormancy = true
 
 						log.Info(e.ctx, "dormant workspace",
 							slog.F("last_used_at", ws.LastUsedAt),
@@ -325,14 +320,24 @@ func (e *Executor) runOnce(t time.Time) Stats {
 						return xerrors.Errorf("post provisioner job to pubsub: %w", err)
 					}
 				}
-				if dormantNotification != nil {
-					_, err = dormancy.NotifyWorkspaceDormant(
+				if shouldNotifyDormancy {
+					_, err = e.notificationsEnqueuer.Enqueue(
 						e.ctx,
-						e.notificationsEnqueuer,
-						*dormantNotification,
+						ws.OwnerID,
+						notifications.TemplateWorkspaceDormant,
+						map[string]string{
+							"name":           ws.Name,
+							"reason":         "inactivity exceeded the dormancy threshold",
+							"timeTilDormant": time.Duration(tmpl.TimeTilDormant).String(),
+						},
+						"lifecycle_executor",
+						ws.ID,
+						ws.OwnerID,
+						ws.TemplateID,
+						ws.OrganizationID,
 					)
 					if err != nil {
-						log.Warn(e.ctx, "failed to notify of workspace marked as dormant", slog.Error(err), slog.F("workspace_id", dormantNotification.Workspace.ID))
+						log.Warn(e.ctx, "failed to notify of workspace marked as dormant", slog.Error(err), slog.F("workspace_id", ws.ID))
 					}
 				}
 				return nil
diff --git a/coderd/autobuild/lifecycle_executor_test.go b/coderd/autobuild/lifecycle_executor_test.go
index 243b2550ccf63..f2fb37c8b471c 100644
--- a/coderd/autobuild/lifecycle_executor_test.go
+++ b/coderd/autobuild/lifecycle_executor_test.go
@@ -1122,7 +1122,6 @@ func TestNotifications(t *testing.T) {
 		require.Contains(t, notifyEnq.Sent[0].Targets, workspace.ID)
 		require.Contains(t, notifyEnq.Sent[0].Targets, workspace.OrganizationID)
 		require.Contains(t, notifyEnq.Sent[0].Targets, workspace.OwnerID)
-		require.Equal(t, notifyEnq.Sent[0].Labels["initiator"], "autobuild")
 	})
 }
 
diff --git a/coderd/database/migrations/000232_update_dormancy_notification_template.down.sql b/coderd/database/migrations/000232_update_dormancy_notification_template.down.sql
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/coderd/database/migrations/000232_update_dormancy_notification_template.up.sql b/coderd/database/migrations/000232_update_dormancy_notification_template.up.sql
new file mode 100644
index 0000000000000..c36502841d86e
--- /dev/null
+++ b/coderd/database/migrations/000232_update_dormancy_notification_template.up.sql
@@ -0,0 +1,16 @@
+UPDATE notification_templates
+SET
+	body_template = E'Hi {{.UserName}}\n\n' ||
+		E'Your workspace **{{.Labels.name}}** has been marked as [**dormant**](https://coder.com/docs/templates/schedule#dormancy-threshold-enterprise) because of {{.Labels.reason}}.\n' ||
+		E'Dormant workspaces are [automatically deleted](https://coder.com/docs/templates/schedule#dormancy-auto-deletion-enterprise) after {{.Labels.timeTilDormant}} of inactivity.\n' ||
+		E'To prevent deletion, use your workspace with the link below.'
+WHERE
+	id = '0ea69165-ec14-4314-91f1-69566ac3c5a0';
+
+UPDATE notification_templates
+SET
+	body_template = E'Hi {{.UserName}}\n\n' ||
+		E'Your workspace **{{.Labels.name}}** has been marked for **deletion** after {{.Labels.timeTilDormant}} of [dormancy](https://coder.com/docs/templates/schedule#dormancy-auto-deletion-enterprise) because of {{.Labels.reason}}.\n' || 
+		E'To prevent deletion, use your workspace with the link below.'
+WHERE
+	id = '51ce2fdf-c9ca-4be1-8d70-628674f9bc42';
diff --git a/coderd/database/queries/notifications.sql b/coderd/database/queries/notifications.sql
index 2fd372e9df029..c0a2f25323957 100644
--- a/coderd/database/queries/notifications.sql
+++ b/coderd/database/queries/notifications.sql
@@ -132,4 +132,3 @@ WHERE id IN
 
 -- name: GetNotificationMessagesByStatus :many
 SELECT * FROM notification_messages WHERE status = @status LIMIT sqlc.arg('limit')::int;
-
diff --git a/coderd/dormancy/notifications.go b/coderd/dormancy/notifications.go
deleted file mode 100644
index 162ca272db635..0000000000000
--- a/coderd/dormancy/notifications.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// This package is located outside of the enterprise package to ensure
-// accessibility in the putWorkspaceDormant function. This design choice allows
-// workspaces to be taken out of dormancy even if the license has expired,
-// ensuring critical functionality remains available without an active
-// enterprise license.
-package dormancy
-
-import (
-	"context"
-
-	"github.com/google/uuid"
-
-	"github.com/coder/coder/v2/coderd/database"
-	"github.com/coder/coder/v2/coderd/notifications"
-)
-
-type WorkspaceDormantNotification struct {
-	Workspace database.Workspace
-	Initiator string
-	Reason    string
-	CreatedBy string
-}
-
-func NotifyWorkspaceDormant(
-	ctx context.Context,
-	enqueuer notifications.Enqueuer,
-	notification WorkspaceDormantNotification,
-) (id *uuid.UUID, err error) {
-	labels := map[string]string{
-		"name":      notification.Workspace.Name,
-		"initiator": notification.Initiator,
-		"reason":    notification.Reason,
-	}
-	return enqueuer.Enqueue(
-		ctx,
-		notification.Workspace.OwnerID,
-		notifications.TemplateWorkspaceDormant,
-		labels,
-		notification.CreatedBy,
-		// Associate this notification with all the related entities.
-		notification.Workspace.ID,
-		notification.Workspace.OwnerID,
-		notification.Workspace.TemplateID,
-		notification.Workspace.OrganizationID,
-	)
-}
-
-type WorkspaceMarkedForDeletionNotification struct {
-	Workspace database.Workspace
-	Reason    string
-	CreatedBy string
-}
-
-func NotifyWorkspaceMarkedForDeletion(
-	ctx context.Context,
-	enqueuer notifications.Enqueuer,
-	notification WorkspaceMarkedForDeletionNotification,
-) (id *uuid.UUID, err error) {
-	labels := map[string]string{
-		"name":   notification.Workspace.Name,
-		"reason": notification.Reason,
-	}
-	return enqueuer.Enqueue(
-		ctx,
-		notification.Workspace.OwnerID,
-		notifications.TemplateWorkspaceMarkedForDeletion,
-		labels,
-		notification.CreatedBy,
-		// Associate this notification with all the related entities.
-		notification.Workspace.ID,
-		notification.Workspace.OwnerID,
-		notification.Workspace.TemplateID,
-		notification.Workspace.OrganizationID,
-	)
-}
diff --git a/coderd/notifications/notifications_test.go b/coderd/notifications/notifications_test.go
index 7d55ac01c5b52..37fe4a2ce5ce3 100644
--- a/coderd/notifications/notifications_test.go
+++ b/coderd/notifications/notifications_test.go
@@ -29,6 +29,7 @@ import (
 	"github.com/coder/coder/v2/coderd/database/dbtestutil"
 	"github.com/coder/coder/v2/coderd/notifications"
 	"github.com/coder/coder/v2/coderd/notifications/dispatch"
+	"github.com/coder/coder/v2/coderd/notifications/render"
 	"github.com/coder/coder/v2/coderd/notifications/types"
 	"github.com/coder/coder/v2/coderd/util/syncmap"
 	"github.com/coder/coder/v2/codersdk"
@@ -603,6 +604,107 @@ func TestNotifierPaused(t *testing.T) {
 	}, testutil.WaitShort, testutil.IntervalFast)
 }
 
+func TestNotifcationTemplatesBody(t *testing.T) {
+	t.Parallel()
+
+	if !dbtestutil.WillUsePostgres() {
+		t.Skip("This test requires postgres; it relies on the notification templates added by migrations in the database")
+	}
+
+	tests := []struct {
+		name    string
+		id      uuid.UUID
+		payload types.MessagePayload
+	}{
+		{
+			name: "TemplateWorkspaceDeleted",
+			id:   notifications.TemplateWorkspaceDeleted,
+			payload: types.MessagePayload{
+				UserName: "bobby",
+				Labels: map[string]string{
+					"name":      "bobby-workspace",
+					"reason":    "autodeleted due to dormancy",
+					"initiator": "autobuild",
+				},
+			},
+		},
+		{
+			name: "TemplateWorkspaceAutobuildFailed",
+			id:   notifications.TemplateWorkspaceAutobuildFailed,
+			payload: types.MessagePayload{
+				UserName: "bobby",
+				Labels: map[string]string{
+					"name":   "bobby-workspace",
+					"reason": "autostart",
+				},
+			},
+		},
+		{
+			name: "TemplateWorkspaceDormant",
+			id:   notifications.TemplateWorkspaceDormant,
+			payload: types.MessagePayload{
+				UserName: "bobby",
+				Labels: map[string]string{
+					"name":          "bobby-workspace",
+					"reason":        "breached the template's threshold for inactivity",
+					"initiator":     "autobuild",
+					"dormancyHours": "24",
+				},
+			},
+		},
+		{
+			name: "TemplateWorkspaceAutoUpdated",
+			id:   notifications.TemplateWorkspaceAutoUpdated,
+			payload: types.MessagePayload{
+				UserName: "bobby",
+				Labels: map[string]string{
+					"name":                  "bobby-workspace",
+					"template_version_name": "1.0",
+				},
+			},
+		},
+		{
+			name: "TemplateWorkspaceMarkedForDeletion",
+			id:   notifications.TemplateWorkspaceMarkedForDeletion,
+			payload: types.MessagePayload{
+				UserName: "bobby",
+				Labels: map[string]string{
+					"name":          "bobby-workspace",
+					"reason":        "template updated to new dormancy policy",
+					"dormancyHours": "24",
+				},
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		tc := tc
+
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+
+			_, _, sql := dbtestutil.NewDBWithSQLDB(t)
+
+			var (
+				titleTmpl string
+				bodyTmpl  string
+			)
+			err := sql.
+				QueryRow("SELECT title_template, body_template FROM notification_templates WHERE id = $1 LIMIT 1", tc.id).
+				Scan(&titleTmpl, &bodyTmpl)
+			require.NoError(t, err, "failed to query body template for template:", tc.id)
+
+			title, err := render.GoTemplate(titleTmpl, tc.payload, nil)
+			require.NoError(t, err, "failed to render notification title template")
+			require.NotEmpty(t, title, "title should not be empty")
+
+			body, err := render.GoTemplate(bodyTmpl, tc.payload, nil)
+			require.NoError(t, err, "failed to render notification body template")
+			require.NotEmpty(t, body, "body should not be empty")
+		})
+	}
+}
+
 type fakeHandler struct {
 	mu                sync.RWMutex
 	succeeded, failed []string
diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go
index b71935e9a0436..458f79ca348e6 100644
--- a/coderd/provisionerdserver/provisionerdserver.go
+++ b/coderd/provisionerdserver/provisionerdserver.go
@@ -1101,13 +1101,11 @@ func (s *server) notifyWorkspaceBuildFailed(ctx context.Context, workspace datab
 		return // failed workspace build initiated by a user should not notify
 	}
 	reason = string(build.Reason)
-	initiator := "autobuild"
 
 	if _, err := s.NotificationsEnqueuer.Enqueue(ctx, workspace.OwnerID, notifications.TemplateWorkspaceAutobuildFailed,
 		map[string]string{
-			"name":      workspace.Name,
-			"initiator": initiator,
-			"reason":    reason,
+			"name":   workspace.Name,
+			"reason": reason,
 		}, "provisionerdserver",
 		// Associate this notification with all the related entities.
 		workspace.ID, workspace.OwnerID, workspace.TemplateID, workspace.OrganizationID,
diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go
index 2117d8e5f3df8..79c1b00ac78ee 100644
--- a/coderd/provisionerdserver/provisionerdserver_test.go
+++ b/coderd/provisionerdserver/provisionerdserver_test.go
@@ -1797,7 +1797,6 @@ func TestNotifications(t *testing.T) {
 					require.Contains(t, notifEnq.Sent[0].Targets, workspace.ID)
 					require.Contains(t, notifEnq.Sent[0].Targets, workspace.OrganizationID)
 					require.Contains(t, notifEnq.Sent[0].Targets, user.ID)
-					require.Equal(t, "autobuild", notifEnq.Sent[0].Labels["initiator"])
 					require.Equal(t, string(tc.buildReason), notifEnq.Sent[0].Labels["reason"])
 				} else {
 					require.Len(t, notifEnq.Sent, 0)
diff --git a/coderd/workspaces.go b/coderd/workspaces.go
index 1f4c4f276a5b8..ceba543639cc3 100644
--- a/coderd/workspaces.go
+++ b/coderd/workspaces.go
@@ -23,9 +23,9 @@ import (
 	"github.com/coder/coder/v2/coderd/database/dbauthz"
 	"github.com/coder/coder/v2/coderd/database/dbtime"
 	"github.com/coder/coder/v2/coderd/database/provisionerjobs"
-	"github.com/coder/coder/v2/coderd/dormancy"
 	"github.com/coder/coder/v2/coderd/httpapi"
 	"github.com/coder/coder/v2/coderd/httpmw"
+	"github.com/coder/coder/v2/coderd/notifications"
 	"github.com/coder/coder/v2/coderd/rbac"
 	"github.com/coder/coder/v2/coderd/rbac/policy"
 	"github.com/coder/coder/v2/coderd/schedule/cron"
@@ -953,25 +953,43 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) {
 
 	// We don't need to notify the owner if they are the one making the request.
 	if req.Dormant && apiKey.UserID != workspace.OwnerID {
-		initiator, err := api.Database.GetUserByID(ctx, apiKey.UserID)
-		if err != nil {
+		initiator, initiatorErr := api.Database.GetUserByID(ctx, apiKey.UserID)
+		if initiatorErr != nil {
 			api.Logger.Warn(
 				ctx,
-				"failed to fetch the user that marked the workspace",
+				"failed to fetch the user that marked the workspace as dormant",
 				slog.Error(err),
 				slog.F("workspace_id", workspace.ID),
 				slog.F("user_id", apiKey.UserID),
 			)
-		} else {
-			_, err = dormancy.NotifyWorkspaceDormant(
+		}
+
+		tmpl, tmplErr := api.Database.GetTemplateByID(ctx, workspace.TemplateID)
+		if tmplErr != nil {
+			api.Logger.Warn(
+				ctx,
+				"failed to fetch the template of the workspace marked as dormant",
+				slog.Error(err),
+				slog.F("workspace_id", workspace.ID),
+				slog.F("template_id", workspace.TemplateID),
+			)
+		}
+
+		if initiatorErr == nil && tmplErr == nil {
+			_, err = api.NotificationsEnqueuer.Enqueue(
 				ctx,
-				api.NotificationsEnqueuer,
-				dormancy.WorkspaceDormantNotification{
-					Workspace: workspace,
-					Initiator: initiator.Username,
-					Reason:    "requested by user",
-					CreatedBy: "api",
+				workspace.OwnerID,
+				notifications.TemplateWorkspaceDormant,
+				map[string]string{
+					"name":           workspace.Name,
+					"reason":         "a " + initiator.Username + " request",
+					"timeTilDormant": time.Duration(tmpl.TimeTilDormant).String(),
 				},
+				"api",
+				workspace.ID,
+				workspace.OwnerID,
+				workspace.TemplateID,
+				workspace.OrganizationID,
 			)
 			if err != nil {
 				api.Logger.Warn(ctx, "failed to notify of workspace marked as dormant", slog.Error(err))
diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go
index c2a8c3c9c4ec8..94e89bcd50f98 100644
--- a/coderd/workspaces_test.go
+++ b/coderd/workspaces_test.go
@@ -3457,13 +3457,13 @@ func TestNotifications(t *testing.T) {
 					IncludeProvisionerDaemon: true,
 					NotificationsEnqueuer:    notifyEnq,
 				})
-				user                 = coderdtest.CreateFirstUser(t, client)
-				memberClient, member = coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleOwner())
-				version              = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
-				_                    = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
-				template             = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
-				workspace            = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
-				_                    = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
+				user            = coderdtest.CreateFirstUser(t, client)
+				memberClient, _ = coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleOwner())
+				version         = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
+				_               = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
+				template        = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
+				workspace       = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
+				_               = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
 			)
 
 			ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
@@ -3483,7 +3483,6 @@ func TestNotifications(t *testing.T) {
 			require.Contains(t, notifyEnq.Sent[0].Targets, workspace.ID)
 			require.Contains(t, notifyEnq.Sent[0].Targets, workspace.OrganizationID)
 			require.Contains(t, notifyEnq.Sent[0].Targets, workspace.OwnerID)
-			require.Equal(t, notifyEnq.Sent[0].Labels["initiator"], member.Username)
 		})
 
 		t.Run("InitiatorIsOwner", func(t *testing.T) {
diff --git a/enterprise/coderd/schedule/template.go b/enterprise/coderd/schedule/template.go
index c3cb5001e091c..c38b8f509b5c3 100644
--- a/enterprise/coderd/schedule/template.go
+++ b/enterprise/coderd/schedule/template.go
@@ -16,7 +16,6 @@ import (
 	"github.com/coder/coder/v2/coderd/database"
 	"github.com/coder/coder/v2/coderd/database/dbauthz"
 	"github.com/coder/coder/v2/coderd/database/dbtime"
-	"github.com/coder/coder/v2/coderd/dormancy"
 	"github.com/coder/coder/v2/coderd/notifications"
 	agpl "github.com/coder/coder/v2/coderd/schedule"
 	"github.com/coder/coder/v2/coderd/tracing"
@@ -205,18 +204,25 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
 		return database.Template{}, err
 	}
 
-	for _, workspace := range markedForDeletion {
-		_, err = dormancy.NotifyWorkspaceMarkedForDeletion(
+	for _, ws := range markedForDeletion {
+		_, err = s.enqueuer.Enqueue(
 			ctx,
-			s.enqueuer,
-			dormancy.WorkspaceMarkedForDeletionNotification{
-				Workspace: workspace,
-				Reason:    "template updated to new dormancy policy",
-				CreatedBy: "scheduletemplate",
+			ws.OwnerID,
+			notifications.TemplateWorkspaceMarkedForDeletion,
+			map[string]string{
+				"name":           ws.Name,
+				"reason":         "an update to the template's dormancy",
+				"timeTilDormant": opts.TimeTilDormantAutoDelete.String(),
 			},
+			"scheduletemplate",
+			// Associate this notification with all the related entities.
+			ws.ID,
+			ws.OwnerID,
+			ws.TemplateID,
+			ws.OrganizationID,
 		)
 		if err != nil {
-			s.logger.Warn(ctx, "failed to notify of workspace marked for deletion", slog.Error(err), slog.F("workspace_id", workspace.ID))
+			s.logger.Warn(ctx, "failed to notify of workspace marked for deletion", slog.Error(err), slog.F("workspace_id", ws.ID))
 		}
 	}