diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 76d7d7b40..5340c7c54 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -72,6 +72,18 @@
environment:
- PlantUml__RemoteUrl=
- ConnectionStrings__DefaultConnection=USER ID=tracelens;PASSWORD=tracelenspass;HOST=postgres;PORT=5432;DATABASE=tracelens;POOLING=true;
+
+ smtp4dev: # Mock SMTP server
+ image: rnwood/smtp4dev
+ container_name: smtp4dev
+ restart: always
+ ports:
+ - "3000:80" # Web interface
+ - "2525:25" # SMTP port
+ environment:
+ - ASPNETCORE_URLS=http://+:80
+ - Logging__LogLevel__Default=Information
+
elsa-server:
build:
diff --git a/src/modules/Elsa.Email/Activities/SendEmail.cs b/src/modules/Elsa.Email/Activities/SendEmail.cs
index c1e88afcb..4ec9ca02d 100644
--- a/src/modules/Elsa.Email/Activities/SendEmail.cs
+++ b/src/modules/Elsa.Email/Activities/SendEmail.cs
@@ -84,8 +84,7 @@ public class SendEmail : Activity
///
/// The activity to execute when an error occurs while trying to send the email.
///
- [Port]
- public IActivity? Error { get; set; }
+ [Port] public IActivity? Error { get; set; }
///
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
@@ -99,7 +98,10 @@ public class SendEmail : Activity
message.From.Add(MailboxAddress.Parse(from));
message.Subject = Subject.GetOrDefault(context) ?? "";
- var bodyBuilder = new BodyBuilder { HtmlBody = Body.GetOrDefault(context) };
+ var bodyBuilder = new BodyBuilder
+ {
+ HtmlBody = Body.GetOrDefault(context)
+ };
await AddAttachmentsAsync(context, bodyBuilder, cancellationToken);
message.Body = bodyBuilder.ToMessageBody();
@@ -119,7 +121,10 @@ public class SendEmail : Activity
catch (Exception e)
{
logger.LogWarning(e, "Error while sending email message");
- context.AddExecutionLogEntry("Error", e.Message, payload: new { e.StackTrace });
+ context.AddExecutionLogEntry("Error", e.Message, payload: new
+ {
+ e.StackTrace
+ });
await context.ScheduleActivityAsync(Error, OnErrorCompletedAsync);
}
}
@@ -155,38 +160,38 @@ public class SendEmail : Activity
await AttachLocalFileAsync(bodyBuilder, path, cancellationToken);
break;
case byte[] bytes:
- {
- var fileName = $"Attachment-{++index}";
- bodyBuilder.Attachments.Add(fileName, bytes, ContentType.Parse("application/binary"));
- break;
- }
+ {
+ var fileName = $"Attachment-{++index}";
+ bodyBuilder.Attachments.Add(fileName, bytes, ContentType.Parse("application/binary"));
+ break;
+ }
case Stream stream:
- {
- var fileName = $"Attachment-{++index}";
- await bodyBuilder.Attachments.AddAsync(fileName, stream, ContentType.Parse("application/binary"), cancellationToken);
- break;
- }
+ {
+ var fileName = $"Attachment-{++index}";
+ await bodyBuilder.Attachments.AddAsync(fileName, stream, ContentType.Parse("application/binary"), cancellationToken);
+ break;
+ }
case EmailAttachment emailAttachment:
- {
- var fileName = emailAttachment.FileName ?? $"Attachment-{++index}";
- var contentType = emailAttachment.ContentType ?? "application/binary";
- var parsedContentType = ContentType.Parse(contentType);
+ {
+ var fileName = emailAttachment.FileName ?? $"Attachment-{++index}";
+ var contentType = emailAttachment.ContentType ?? "application/binary";
+ var parsedContentType = ContentType.Parse(contentType);
- if (emailAttachment.Content is byte[] bytes)
- bodyBuilder.Attachments.Add(fileName, bytes, parsedContentType);
+ if (emailAttachment.Content is byte[] bytes)
+ bodyBuilder.Attachments.Add(fileName, bytes, parsedContentType);
- else if (emailAttachment.Content is Stream stream)
- await bodyBuilder.Attachments.AddAsync(fileName, stream, parsedContentType, cancellationToken);
+ else if (emailAttachment.Content is Stream stream)
+ await bodyBuilder.Attachments.AddAsync(fileName, stream, parsedContentType, cancellationToken);
- break;
- }
+ break;
+ }
default:
- {
- var json = JsonSerializer.Serialize(attachmentObject);
- var fileName = $"Attachment-{++index}";
- bodyBuilder.Attachments.Add(fileName, Encoding.UTF8.GetBytes(json), ContentType.Parse("application/json"));
- break;
- }
+ {
+ var json = JsonSerializer.Serialize(attachmentObject);
+ var fileName = $"Attachment-{++index}";
+ bodyBuilder.Attachments.Add(fileName, Encoding.UTF8.GetBytes(json), ContentType.Parse("application/json"));
+ break;
+ }
}
}
}
@@ -203,7 +208,24 @@ public class SendEmail : Activity
await bodyBuilder.Attachments.AddAsync(fileName, contentStream, ContentType.Parse(contentType), cancellationToken);
}
- private IEnumerable InterpretAttachmentsModel(object attachments) => attachments is string text ? new[] { text } : attachments is IEnumerable enumerable ? enumerable : new[] { attachments };
+ private IEnumerable InterpretAttachmentsModel(object attachments)
+ {
+ if (attachments is byte[] bytes)
+ return new[]
+ {
+ bytes
+ };
+
+ return attachments is string text
+ ? new[]
+ {
+ text
+ }
+ : attachments as IEnumerable ?? new[]
+ {
+ attachments
+ };
+ }
private void SetRecipientsEmailAddresses(InternetAddressList list, IEnumerable? addresses)
{
diff --git a/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs b/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs
index 1d0e0e934..48c481de0 100644
--- a/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs
+++ b/src/modules/Elsa.Workflows.Management/Mappers/VariableDefinitionMapper.cs
@@ -18,10 +18,16 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist
///
public Variable? Map(VariableDefinition source)
{
- if (!wellKnownTypeRegistry.TryGetTypeOrDefault(source.TypeName, out var type))
+ var aliasedType = wellKnownTypeRegistry.TryGetType(source.TypeName, out var aliasedTypeValue) ? aliasedTypeValue : null;
+ var type = aliasedType ?? Type.GetType(source.TypeName);
+
+ if(type == null)
+ {
+ logger.LogWarning("Failed to resolve the type {TypeName} of variable {VariableName}. Variable will not be mapped.", source.TypeName, source.Name);
return null;
+ }
- var valueType = source.IsArray ? type.MakeArrayType() : type;
+ var valueType = aliasedType ?? (source.IsArray ? type.MakeArrayType() : type);
var variableGenericType = typeof(Variable<>).MakeGenericType(valueType);
var variable = (Variable)Activator.CreateInstance(variableGenericType)!;
@@ -58,15 +64,20 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist
{
var variableType = source.GetType();
var valueType = variableType.IsConstructedGenericType ? variableType.GetGenericArguments().FirstOrDefault() ?? typeof(object) : typeof(object);
+ var valueTypeAlias = wellKnownTypeRegistry.TryGetAlias(valueType, out var alias) ? alias : null;
+ var value = source.Value;
+ var serializedValue = value.Format();
+ var storageDriverTypeName = source.StorageDriverType?.GetSimpleAssemblyQualifiedName();
+
+ if(valueTypeAlias != null)
+ return new(source.Id, source.Name, valueTypeAlias, false, serializedValue, storageDriverTypeName);
+
var isArray = valueType.IsArray;
var isCollection = valueType.IsCollectionType();
var elementValueType = isArray ? valueType.GetElementType() : isCollection ? valueType.GenericTypeArguments[0] : valueType;
- var value = source.Value;
- var valueTypeAlias = wellKnownTypeRegistry.GetAliasOrDefault(elementValueType);
- var storageDriverTypeName = source.StorageDriverType?.GetSimpleAssemblyQualifiedName();
- var serializedValue = value.Format();
-
- return new(source.Id, source.Name, valueTypeAlias, isArray, serializedValue, storageDriverTypeName);
+ var elementTypeAlias = wellKnownTypeRegistry.GetAliasOrDefault(elementValueType);
+
+ return new(source.Id, source.Name, elementTypeAlias, isArray, serializedValue, storageDriverTypeName);
}
///