• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

djsuperchief / Kyameru / 15155278996

21 May 2025 06:38AM UTC coverage: 87.848% (-3.2%) from 91.081%
15155278996

push

github

web-flow
Merge pull request #195 from djsuperchief/189-atomic-remove

189 Go Live

501 of 630 branches covered (79.52%)

Branch coverage included in aggregate %.

175 of 203 new or added lines in 21 files covered. (86.21%)

93 existing lines in 13 files now uncovered.

2875 of 3213 relevant lines covered (89.48%)

22.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.19
/source/components/Kyameru.Component.Ses/Implementation/SesTo.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Threading;
5
using System.Threading.Tasks;
6
using Amazon.SimpleEmail;
7
using Amazon.SimpleEmail.Model;
8
using Kyameru.Core.Entities;
9
using Microsoft.Extensions.Logging;
10

11
namespace Kyameru.Component.Ses;
12

13
public class SesTo : ITo
14
{
15
    private const string CharSet = "UTF-8";
16
    private readonly IAmazonSimpleEmailService sesClient;
17
    private Dictionary<string, string> headers;
18

19
    public event EventHandler<Log> OnLog;
20

21
    public SesTo(IAmazonSimpleEmailService ses)
6✔
22
    {
6✔
23
        sesClient = ses;
6✔
24
    }
6✔
25

26
    public void SetHeaders(Dictionary<string, string> incomingHeaders)
27
    {
6✔
28
        headers = incomingHeaders;
6✔
29
    }
6✔
30

31
    public async Task ProcessAsync(Routable routable, CancellationToken cancellationToken)
32
    {
5✔
33
        Validate(routable);
5✔
34
        if (routable.DataType == "SesMessage")
2✔
35
        {
1✔
36
            await SendEmail(routable, cancellationToken);
1✔
37
        }
1✔
38
        else
39
        {
1✔
40
            await SendTemplate(routable, cancellationToken);
1✔
41
        }
1✔
42
    }
2✔
43

44
    private async Task SendTemplate(Routable routable, CancellationToken cancellationToken)
45
    {
1✔
46
        Log(LogLevel.Information, Resources.INFO_SENDING_TEMPLATE);
1✔
47
        var message = routable.Body as SesTemplate;
1✔
48
        var request = new SendTemplatedEmailRequest()
1✔
49
        {
1✔
50
            Source = routable.Headers.TryGetValue("SESFrom", headers["from"]),
1✔
51
            Destination = new Destination()
1✔
52
            {
1✔
53
                ToAddresses = routable.Headers["SESTo"].Split(",").ToList(),
1✔
54
                BccAddresses = GetAddresses(routable, "SESBcc"),
1✔
55
                CcAddresses = GetAddresses(routable, "SESCc"),
1✔
56
            },
1✔
57
            Template = message.Template,
1✔
58
            TemplateData = message.TemplateData
1✔
59
        };
1✔
60

61
        var response = await sesClient.SendTemplatedEmailAsync(request, cancellationToken);
1✔
62
        if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
1✔
63
        {
1✔
64
            foreach (var key in response.ResponseMetadata?.Metadata?.Keys)
7!
65
            {
2✔
66
                routable.SetHeader($"SES{key}", response.ResponseMetadata.Metadata[key]);
2✔
67
            }
2✔
68
        }
1✔
69
    }
1✔
70

71
    private async Task SendEmail(Routable routable, CancellationToken cancellationToken)
72
    {
1✔
73
        Log(LogLevel.Information, Resources.INFO_SENDING_EMAIL);
1✔
74
        var request = new SendEmailRequest()
1✔
75
        {
1✔
76
            Destination = new Destination()
1✔
77
            {
1✔
78
                ToAddresses = routable.Headers["SESTo"].Split(",").ToList(),
1✔
79
                BccAddresses = GetAddresses(routable, "SESBcc"),
1✔
80
                CcAddresses = GetAddresses(routable, "SESCc"),
1✔
81
            },
1✔
82
            Source = routable.Headers.TryGetValue("SESFrom", headers["from"]),
1✔
83
            Message = GetEmailMessage(routable)
1✔
84
        };
1✔
85

86
        var response = await sesClient.SendEmailAsync(request, cancellationToken);
1✔
87
        if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
1✔
88
        {
1✔
89
            foreach (var key in response.ResponseMetadata?.Metadata?.Keys)
7!
90
            {
2✔
91
                routable.SetHeader($"SES{key}", response.ResponseMetadata.Metadata[key]);
2✔
92
            }
2✔
93
        }
1✔
94
    }
1✔
95

96
    private Message GetEmailMessage(Routable routable)
97
    {
1✔
98
        var message = new Message()
1✔
99
        {
1✔
100
            Body = new Body()
1✔
101
        };
1✔
102
        var bodyData = routable.Body as SesMessage;
1✔
103
        if (!string.IsNullOrWhiteSpace(bodyData.BodyHtml))
1✔
104
        {
1✔
105
            message.Body.Html = new Content()
1✔
106
            {
1✔
107
                Charset = CharSet,
1✔
108
                Data = bodyData.BodyHtml
1✔
109
            };
1✔
110

111
        }
1✔
112

113
        if (!string.IsNullOrWhiteSpace(bodyData.BodyText))
1✔
114
        {
1✔
115
            message.Body.Text = new Content()
1✔
116
            {
1✔
117
                Charset = CharSet,
1✔
118
                Data = bodyData.BodyText
1✔
119
            };
1✔
120
        }
1✔
121

122
        if (!string.IsNullOrWhiteSpace(bodyData.Subject))
1✔
123
        {
1✔
124
            message.Subject = new Content()
1✔
125
            {
1✔
126
                Charset = CharSet,
1✔
127
                Data = bodyData.Subject
1✔
128
            };
1✔
129
        }
1✔
130

131
        return message;
1✔
132
    }
1✔
133

134
    private List<string> GetAddresses(Routable routable, string key)
135
    {
4✔
136
        var output = routable.Headers.TryGetValue(key);
4✔
137
        if (!string.IsNullOrWhiteSpace(output))
4!
138
        {
×
139
            return output.Split(',').ToList();
×
140
        }
141

142
        return new List<string>();
4✔
143
    }
4✔
144

145
    private void Validate(Routable routable)
146
    {
5✔
147
        headers.TryGetValue("from", out var from);
5✔
148
        routable.Headers.TryGetValue("SESFrom", from);
5✔
149

150
        if (string.IsNullOrWhiteSpace(from))
5!
151
        {
×
152
            throw new Exceptions.MissingInformationException(string.Format(Resources.EXCEPTION_MISSINGINFORMATION, "From Address"));
×
153
        }
154

155
        if (routable.Headers["DataType"] != "SesMessage" && routable.Headers["DataType"] != "SesTemplate")
5✔
156
        {
1✔
157
            throw new Exceptions.DataTypeException(Resources.EXCEPTION_INCORRECTDATATYPE);
1✔
158
        }
159

160
        if (routable.DataType == "SesMessage")
4✔
161
        {
3✔
162
            var message = routable.Body as SesMessage;
3✔
163
            if (string.IsNullOrWhiteSpace(message.BodyHtml) && string.IsNullOrWhiteSpace(message.BodyText))
3✔
164
            {
1✔
165
                throw new Exceptions.MissingInformationException(Resources.EXCEPTION_BODYMISSING);
1✔
166
            }
167
        }
2✔
168
        else
169
        {
1✔
170
            var message = routable.Body as SesTemplate;
1✔
171
            if (string.IsNullOrWhiteSpace(message.Template) || string.IsNullOrWhiteSpace(message.TemplateData))
1!
172
            {
×
173
                throw new Exceptions.MissingInformationException(Resources.EXCEPTION_TEMPLATEMISSINGDATA);
×
174
            }
175
        }
1✔
176

177
        var to = routable.Headers.TryGetValue("SESTo");
3✔
178
        if (string.IsNullOrWhiteSpace(to) || to.Split(',').Count() <= 0)
3✔
179
        {
1✔
180
            throw new Exceptions.MissingInformationException(string.Format(Resources.EXCEPTION_MISSINGINFORMATION, "To Addresses"));
1✔
181
        }
182
    }
2✔
183

184
    private void Log(LogLevel logLevel, string message, Exception exception = null)
185
    {
2✔
186
        if (OnLog != null)
2!
NEW
187
        {
×
NEW
188
            OnLog?.Invoke(this, new Core.Entities.Log(logLevel, message, exception));
×
NEW
189
        }
×
190
    }
2✔
191
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc