diff --git a/models/action.go b/models/action.go
index 59ccdb2d4c..d6dbcdc671 100644
--- a/models/action.go
+++ b/models/action.go
@@ -49,6 +49,7 @@ const (
 	ActionApprovePullRequest                       // 21
 	ActionRejectPullRequest                        // 22
 	ActionCommentPull                              // 23
+	ActionPublishRelease                           // 24
 )
 
 // Action represents user operation type and other information to
diff --git a/models/repo_watch.go b/models/repo_watch.go
index 11cfa88918..6cdf9b2af5 100644
--- a/models/repo_watch.go
+++ b/models/repo_watch.go
@@ -252,7 +252,7 @@ func notifyWatchers(e Engine, actions ...*Action) error {
 			act.Repo.Units = nil
 
 			switch act.OpType {
-			case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionDeleteBranch:
+			case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionPublishRelease, ActionDeleteBranch:
 				if !permCode[i] {
 					continue
 				}
diff --git a/modules/notification/action/action.go b/modules/notification/action/action.go
index 9956940f30..040cf3df10 100644
--- a/modules/notification/action/action.go
+++ b/modules/notification/action/action.go
@@ -314,3 +314,22 @@ func (a *actionNotifier) NotifySyncDeleteRef(doer *models.User, repo *models.Rep
 		log.Error("notifyWatchers: %v", err)
 	}
 }
+
+func (a *actionNotifier) NotifyNewRelease(rel *models.Release) {
+	if err := rel.LoadAttributes(); err != nil {
+		log.Error("NotifyNewRelease: %v", err)
+		return
+	}
+	if err := models.NotifyWatchers(&models.Action{
+		ActUserID: rel.PublisherID,
+		ActUser:   rel.Publisher,
+		OpType:    models.ActionPublishRelease,
+		RepoID:    rel.RepoID,
+		Repo:      rel.Repo,
+		IsPrivate: rel.Repo.IsPrivate,
+		Content:   rel.Title,
+		RefName:   rel.TagName,
+	}); err != nil {
+		log.Error("notifyWatchers: %v", err)
+	}
+}
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index 8c078a0e82..8f3fba618d 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -640,6 +640,8 @@ func ActionIcon(opType models.ActionType) string {
 		return "check"
 	case models.ActionRejectPullRequest:
 		return "diff"
+	case models.ActionPublishRelease:
+		return "tag"
 	default:
 		return "question"
 	}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 7968d00b58..751cce6583 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -2331,6 +2331,7 @@ mirror_sync_create = synced new reference <a href="%s/src/%s">%[2]s</a> to <a hr
 mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror
 approve_pull_request = `approved <a href="%s/pulls/%s">%s#%[2]s</a>`
 reject_pull_request = `suggested changes for <a href="%s/pulls/%s">%s#%[2]s</a>`
+publish_release  = `released <a href="%s/releases/tag/%s"> "%[4]s" </a> at <a href="%[1]s">%[3]s</a>`
 
 [tool]
 ago = %s ago
diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go
index ade82f24cb..752b5c76e0 100644
--- a/routers/api/v1/repo/release.go
+++ b/routers/api/v1/repo/release.go
@@ -194,8 +194,8 @@ func CreateRelease(ctx *context.APIContext, form api.CreateReleaseOption) {
 		rel.Repo = ctx.Repo.Repository
 		rel.Publisher = ctx.User
 
-		if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, nil); err != nil {
-			ctx.ServerError("UpdateRelease", err)
+		if err = releaseservice.UpdateReleaseOrCreatReleaseFromTag(ctx.User, ctx.Repo.GitRepo, rel, nil, true); err != nil {
+			ctx.ServerError("UpdateReleaseOrCreatReleaseFromTag", err)
 			return
 		}
 	}
@@ -266,8 +266,8 @@ func EditRelease(ctx *context.APIContext, form api.EditReleaseOption) {
 	if form.IsPrerelease != nil {
 		rel.IsPrerelease = *form.IsPrerelease
 	}
-	if err := releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, nil); err != nil {
-		ctx.Error(http.StatusInternalServerError, "UpdateRelease", err)
+	if err := releaseservice.UpdateReleaseOrCreatReleaseFromTag(ctx.User, ctx.Repo.GitRepo, rel, nil, false); err != nil {
+		ctx.Error(http.StatusInternalServerError, "UpdateReleaseOrCreatReleaseFromTag", err)
 		return
 	}
 
diff --git a/routers/repo/release.go b/routers/repo/release.go
index 3b8e55f002..02fbcaccaf 100644
--- a/routers/repo/release.go
+++ b/routers/repo/release.go
@@ -223,7 +223,7 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
 			return
 		}
 
-		rel := &models.Release{
+		rel = &models.Release{
 			RepoID:       ctx.Repo.Repository.ID,
 			PublisherID:  ctx.User.ID,
 			Title:        form.Title,
@@ -262,9 +262,9 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
 		rel.PublisherID = ctx.User.ID
 		rel.IsTag = false
 
-		if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
+		if err = releaseservice.UpdateReleaseOrCreatReleaseFromTag(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs, true); err != nil {
 			ctx.Data["Err_TagName"] = true
-			ctx.ServerError("UpdateRelease", err)
+			ctx.ServerError("UpdateReleaseOrCreatReleaseFromTag", err)
 			return
 		}
 	}
@@ -341,7 +341,7 @@ func EditReleasePost(ctx *context.Context, form auth.EditReleaseForm) {
 	rel.Note = form.Content
 	rel.IsDraft = len(form.Draft) > 0
 	rel.IsPrerelease = form.Prerelease
-	if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
+	if err = releaseservice.UpdateReleaseOrCreatReleaseFromTag(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs, false); err != nil {
 		ctx.ServerError("UpdateRelease", err)
 		return
 	}
diff --git a/services/release/release.go b/services/release/release.go
index 64d132cd73..2fc3cb199b 100644
--- a/services/release/release.go
+++ b/services/release/release.go
@@ -95,8 +95,8 @@ func CreateRelease(gitRepo *git.Repository, rel *models.Release, attachmentUUIDs
 	return nil
 }
 
-// UpdateRelease updates information of a release.
-func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Release, attachmentUUIDs []string) (err error) {
+// UpdateReleaseOrCreatReleaseFromTag updates information of a release or create release from tag.
+func UpdateReleaseOrCreatReleaseFromTag(doer *models.User, gitRepo *git.Repository, rel *models.Release, attachmentUUIDs []string, isCreate bool) (err error) {
 	if err = createTag(gitRepo, rel); err != nil {
 		return err
 	}
@@ -110,7 +110,14 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea
 		log.Error("AddReleaseAttachments: %v", err)
 	}
 
-	notification.NotifyUpdateRelease(doer, rel)
+	if !isCreate {
+		notification.NotifyUpdateRelease(doer, rel)
+		return
+	}
+
+	if !rel.IsDraft {
+		notification.NotifyNewRelease(rel)
+	}
 
 	return err
 }
diff --git a/services/release/release_test.go b/services/release/release_test.go
index d5673b73b8..f50fca71ec 100644
--- a/services/release/release_test.go
+++ b/services/release/release_test.go
@@ -131,7 +131,7 @@ func TestRelease_Update(t *testing.T) {
 	releaseCreatedUnix := release.CreatedUnix
 	time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
 	release.Note = "Changed note"
-	assert.NoError(t, UpdateRelease(user, gitRepo, release, nil))
+	assert.NoError(t, UpdateReleaseOrCreatReleaseFromTag(user, gitRepo, release, nil, false))
 	release, err = models.GetReleaseByID(release.ID)
 	assert.NoError(t, err)
 	assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
@@ -153,7 +153,7 @@ func TestRelease_Update(t *testing.T) {
 	releaseCreatedUnix = release.CreatedUnix
 	time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
 	release.Title = "Changed title"
-	assert.NoError(t, UpdateRelease(user, gitRepo, release, nil))
+	assert.NoError(t, UpdateReleaseOrCreatReleaseFromTag(user, gitRepo, release, nil, false))
 	release, err = models.GetReleaseByID(release.ID)
 	assert.NoError(t, err)
 	assert.Less(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
@@ -176,7 +176,7 @@ func TestRelease_Update(t *testing.T) {
 	time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
 	release.Title = "Changed title"
 	release.Note = "Changed note"
-	assert.NoError(t, UpdateRelease(user, gitRepo, release, nil))
+	assert.NoError(t, UpdateReleaseOrCreatReleaseFromTag(user, gitRepo, release, nil, false))
 	release, err = models.GetReleaseByID(release.ID)
 	assert.NoError(t, err)
 	assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl
index a67fe54849..5e6d53e18a 100644
--- a/templates/user/dashboard/feeds.tmpl
+++ b/templates/user/dashboard/feeds.tmpl
@@ -70,6 +70,10 @@
 						{{else if eq .GetOpType 23}}
 							{{ $index := index .GetIssueInfos 0}}
 							{{$.i18n.Tr "action.comment_pull" .GetRepoLink $index .ShortRepoPath | Str2html}}
+						{{else if eq .GetOpType 24}}
+							{{ $branchLink := .GetBranch | EscapePound | Escape}}
+							{{ $linkText := .Content | RenderEmoji }}
+							{{$.i18n.Tr "action.publish_release" .GetRepoLink $branchLink .ShortRepoPath $linkText | Str2html}}
 						{{end}}
 					</p>
 					{{if or (eq .GetOpType 5) (eq .GetOpType 18)}}