// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using System.ComponentModel.DataAnnotations; using MailKit.Net.Smtp; using MimeKit; using MimeKit.Text; using Squidex.Domain.Apps.Core.Rules.Deprecated; using Squidex.Flows; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Validation; namespace Squidex.Extensions.Actions.Email; [FlowStep( Title = "Email", IconImage = "", IconColor = "#333300", Display = "Send an email", Description = "Send an email with a custom SMTP server.", ReadMore = "https://en.wikipedia.org/wiki/Email")] #pragma warning disable CS0618 // Type or member is obsolete internal sealed record EmailFlowStep : FlowStep, IConvertibleToAction #pragma warning restore CS0618 // Type or member is obsolete { [LocalizedRequired] [Display(Name = "Server Host", Description = "The IP address or host to the SMTP server.")] [Editor(FlowStepEditor.Text)] public string ServerHost { get; set; } [LocalizedRequired] [Display(Name = "Server Port", Description = "The port to the SMTP server.")] [Editor(FlowStepEditor.Text)] public int ServerPort { get; set; } [Display(Name = "Username", Description = "The username for the SMTP server.")] [Editor(FlowStepEditor.Text)] [Expression] public string ServerUsername { get; set; } [Display(Name = "Password", Description = "The password for the SMTP server.")] [Editor(FlowStepEditor.Password)] public string ServerPassword { get; set; } [LocalizedRequired] [Display(Name = "From Address", Description = "The email sending address.")] [Editor(FlowStepEditor.Text)] [Expression] public string MessageFrom { get; set; } [LocalizedRequired] [Display(Name = "To Address", Description = "The email message will be sent to.")] [Editor(FlowStepEditor.Text)] [Expression] public string MessageTo { get; set; } [LocalizedRequired] [Display(Name = "Subject", Description = "The subject line for this email message.")] [Editor(FlowStepEditor.Text)] [Expression] public string MessageSubject { get; set; } [LocalizedRequired] [Display(Name = "Body", Description = "The message body.")] [Editor(FlowStepEditor.TextArea)] [Expression] public string MessageBody { get; set; } public override async ValueTask ExecuteAsync(FlowExecutionContext executionContext, CancellationToken ct) { if (executionContext.IsSimulation) { executionContext.LogSkipSimulation(); return Next(); } using var smtpClient = new SmtpClient(); await smtpClient.ConnectAsync(ServerHost, ServerPort, cancellationToken: ct); if (!string.IsNullOrWhiteSpace(ServerUsername) && !string.IsNullOrWhiteSpace(ServerPassword)) { await smtpClient.AuthenticateAsync(ServerUsername, ServerPassword, ct); } var smtpMessage = new MimeMessage { Body = new TextPart(TextFormat.Html) { Text = MessageBody, }, Subject = MessageSubject, }; smtpMessage.From.Add(MailboxAddress.Parse( MessageFrom)); smtpMessage.To.Add(MailboxAddress.Parse( MessageTo)); await smtpClient.SendAsync(smtpMessage, ct); executionContext.Log($"Email sent to {MessageTo}"); return Next(); } #pragma warning disable CS0618 // Type or member is obsolete public RuleAction ToAction() { return SimpleMapper.Map(this, new EmailAction()); } #pragma warning restore CS0618 // Type or member is obsolete }