Skip to content

Commit

Permalink
Make the API public and document it. (#1376)
Browse files Browse the repository at this point in the history
* fix(API): #474 recipient properties should be array typed.
* Document API and ensure not found = 404
  • Loading branch information
rnwood committed Apr 14, 2024
1 parent 6cd9dcd commit 0337655
Show file tree
Hide file tree
Showing 34 changed files with 469 additions and 287 deletions.
1 change: 1 addition & 0 deletions .vscode/launch.json
Expand Up @@ -13,6 +13,7 @@
"args": "--urls http://localhost:5000",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "build"

},
{
Expand Down
3 changes: 2 additions & 1 deletion README.md
@@ -1,7 +1,7 @@
# <img src='Rnwood.Smtp4dev/ClientApp/public/logo.png' alt='logo'/>
**smtp4dev - the fake SMTP email server for development and testing.**

A dummy SMTP server for Windows, Linux, Mac OS-X (and maybe elsewhere where .NET Core is available). Lets you test your application without spamming your real customers and without needing to set up a complicated real email server with a special configuration. Messages received in smtp4dev can be viewed and inspected.
A dummy SMTP server for Windows, Linux, Mac OS-X (and maybe elsewhere where .NET Core is available). Lets you test your application without spamming your real customers and without needing to set up a complicated real email server with a special configuration. Messages received in smtp4dev can be viewed and inspected. There is an API you can use for automated tests.

*If you're looking for the older v2 Windows only GUI version. [Grab it here](https://github.com/rnwood/smtp4dev/releases/tag/v2.0.10).*

Expand All @@ -16,6 +16,7 @@ A dummy SMTP server for Windows, Linux, Mac OS-X (and maybe elsewhere where .NET

[Configuring your programs to send mails to smtp4dev](https://github.com/rnwood/smtp4dev/wiki/Configuring-Clients)

[API] (https://github.com/rnwood/smtp4dev/wiki/API)

## Screenshots

Expand Down
6 changes: 3 additions & 3 deletions Rnwood.Smtp4dev.Tests/Controllers/MessagesControllerTests.cs
Expand Up @@ -37,9 +37,9 @@ public async Task GetMessage_ValidMime()
Assert.Equal(testMessage1.Id, result.Id);
Assert.InRange(result.ReceivedDate, startDate, DateTime.Now);
Assert.Equal("from@message.com", result.From);
Assert.Equal("to@message.com", result.To);
Assert.Equal("to@envelope.com", result.Bcc);
Assert.Equal("cc@message.com", result.Cc);
Assert.Equal(new[]{"to@message.com"}, result.To);
Assert.Equal(new[]{"to@envelope.com"}, result.Bcc);
Assert.Equal(new[]{"cc@message.com"}, result.Cc);
Assert.Equal("subject", result.Subject);

var allParts = result.Parts.Flatten(p => p.ChildParts).ToList();
Expand Down
@@ -1,6 +1,6 @@
namespace Rnwood.Smtp4dev.ApiModel
{
public class Client
public class ClientSettings
{
public int PageSize { get; set; }
}
Expand Down
39 changes: 21 additions & 18 deletions Rnwood.Smtp4dev/ApiModel/Message.cs
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json.Serialization;

namespace Rnwood.Smtp4dev.ApiModel
{
Expand All @@ -15,9 +16,9 @@ public Message(DbModel.Message dbMessage)
Data = dbMessage.Data;
Id = dbMessage.Id;
From = dbMessage.From;
To = dbMessage.To;
Cc = "";
Bcc = "";
To = dbMessage.To.Split(',');
Cc = Array.Empty<string>();
Bcc = Array.Empty<string>();
ReceivedDate = dbMessage.ReceivedDate;
Subject = dbMessage.Subject;
SecureConnection = dbMessage.SecureConnection;
Expand Down Expand Up @@ -49,27 +50,27 @@ public Message(DbModel.Message dbMessage)

if (MimeMessage.To != null)
{
To = string.Join(", ", MimeMessage.To.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())));
To = MimeMessage.To.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())).ToArray();

foreach (var internetAddress in MimeMessage.To.Where(t => t is MailboxAddress))
{
var to = (MailboxAddress) internetAddress;
var to = (MailboxAddress)internetAddress;
recipients.Remove(PunyCodeReplacer.DecodePunycode(to.Address));
}
}

if (MimeMessage.Cc != null)
{
Cc = string.Join(", ", MimeMessage.Cc.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())));
Cc = MimeMessage.Cc.Select(t => PunyCodeReplacer.DecodePunycode(t.ToString())).ToArray();

foreach (var internetAddress in MimeMessage.Cc.Where(t => t is MailboxAddress))
{
var cc = (MailboxAddress) internetAddress;
var cc = (MailboxAddress)internetAddress;
recipients.Remove(PunyCodeReplacer.DecodePunycode(cc.Address));
}
}

Bcc = string.Join(", ", recipients);
Bcc = recipients.ToArray();

Headers = MimeMessage.Headers.Select(h => new Header { Name = h.Field, Value = PunyCodeReplacer.DecodePunycode(h.Value) }).ToList();
Parts.Add(HandleMimeEntity(MimeMessage.Body));
Expand Down Expand Up @@ -148,8 +149,8 @@ internal static FileStreamResult GetPartContent(Message result, string cid)
{
return new FileStreamResult(mimePart.Content.Open(), contentEntity.ContentType?.MimeType ?? "application/text")
{
FileDownloadName = mimePart.FileName ??
((contentEntity.ContentId ?? "content") + (MimeTypes.TryGetExtension(mimePart.ContentType.MimeType, out string extn) ? extn : ""))
FileDownloadName = mimePart.FileName ??
((contentEntity.ContentId ?? "content") + (MimeTypes.TryGetExtension(mimePart.ContentType.MimeType, out string extn) ? extn : ""))
};
}
else
Expand All @@ -169,7 +170,7 @@ internal static FileStreamResult GetPartContent(Message result, string cid)
internal static string GetPartContentAsText(Message result, string id)
{
var contentEntity = GetPart(result, id);

if (contentEntity is MimePart part)
{
var encoding = part.ContentType.CharsetEncoding ?? ApiModel.Message.GetSessionEncodingOrAssumed(result);
Expand All @@ -193,7 +194,7 @@ internal static string GetPartSource(Message message, string id)
using (MemoryStream ms = new MemoryStream())
{
contentEntity.WriteTo(ms, false);
var encoding = contentEntity.ContentType.CharsetEncoding ??ApiModel.Message.GetSessionEncodingOrAssumed(message);
var encoding = contentEntity.ContentType.CharsetEncoding ?? ApiModel.Message.GetSessionEncodingOrAssumed(message);
return encoding.GetString(ms.GetBuffer());
}

Expand All @@ -215,27 +216,29 @@ private static MimeEntity GetPart(Message message, string id)
public Guid Id { get; set; }

public string From { get; set; }
public string To { get; set; }
public string Cc { get; set; }
public string Bcc { get; set; }
public string[] To { get; set; }
public string[] Cc { get; set; }
public string[] Bcc { get; set; }
public DateTime ReceivedDate { get; set; }

public bool SecureConnection { get; set; }

public string Subject { get; set; }

public List<MessageEntitySummary> Parts { get; set; }
public List<MessageEntitySummary> Parts { get; set; }

public List<Header> Headers { get; set; }

public string MimeParseError { get; set; }

public string RelayError { get; set; }

[JsonIgnore]
internal MimeMessage MimeMessage { get; set; }

internal byte[] Data { get; set; }

string ICacheByKey.CacheKey => Id.ToString();
[JsonIgnore]
string ICacheByKey.CacheKey => Id.ToString() + "v2";
}
}
9 changes: 6 additions & 3 deletions Rnwood.Smtp4dev/ApiModel/MessageSummary.cs
@@ -1,4 +1,5 @@
using System;
using System.Text.Json.Serialization;

namespace Rnwood.Smtp4dev.ApiModel
{
Expand All @@ -8,7 +9,7 @@ public MessageSummary(DbModel.Message dbMessage)
{
Id = dbMessage.Id;
From = dbMessage.From;
To = dbMessage.To;
To = dbMessage.To.Split(',');
ReceivedDate = dbMessage.ReceivedDate;
Subject = dbMessage.Subject;
AttachmentCount = dbMessage.AttachmentCount;
Expand All @@ -21,7 +22,7 @@ public MessageSummary(DbModel.Message dbMessage)
public Guid Id { get; set; }

public string From { get; set; }
public string To { get; set; }
public string[] To { get; set; }
public DateTime ReceivedDate { get; set; }

public string Subject { get; set; }
Expand All @@ -30,6 +31,8 @@ public MessageSummary(DbModel.Message dbMessage)

public bool IsUnread { get; set; }

string ICacheByKey.CacheKey => Id.ToString() + IsUnread + IsRelayed;

[JsonIgnore]
string ICacheByKey.CacheKey => Id.ToString() + IsUnread + IsRelayed + "v2";
}
}
3 changes: 3 additions & 0 deletions Rnwood.Smtp4dev/ApiModel/SessionSummary.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Rnwood.Smtp4dev.ApiModel
Expand Down Expand Up @@ -29,6 +30,8 @@ public SessionSummary(DbModel.Session dbSession)

public int Size { get; private set; }


[JsonIgnore]
string ICacheByKey.CacheKey => Id.ToString();
}
}
@@ -1,6 +1,6 @@
namespace Rnwood.Smtp4dev.ApiModel
{
public class Info
public class VersionInfo
{
public string Version { get; set; }
public string InfoVersion { get; set; }
Expand Down
14 changes: 0 additions & 14 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/ClientController.ts

This file was deleted.

@@ -1,4 +1,4 @@
export default class Client {
export default class ClientSettings {
constructor(pageSize: number) {
this.pageSize = pageSize;
}
Expand Down
@@ -0,0 +1,14 @@
import ClientSettings from "./ClientSettings";
import axios from "axios";

export default class ClientSettingsController {
constructor() {}

public getClientSettings_url(): string {
return `api/clientsettings`;
}

public async getClientSettings(): Promise<ClientSettings> {
return (await axios.get(this.getClientSettings_url())).data as ClientSettings;
}
}
15 changes: 0 additions & 15 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/InfoController.ts

This file was deleted.

12 changes: 6 additions & 6 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/Message.ts
Expand Up @@ -6,9 +6,9 @@ export default class Message {
constructor(
id: string,
from: string,
to: string,
cc: string,
bcc: string,
to: string[],
cc: string[],
bcc: string[],
receivedDate: Date,
subject: string,
parts: MessageEntitySummary[],
Expand Down Expand Up @@ -37,9 +37,9 @@ export default class Message {

id: string;
from: string;
to: string;
cc: string;
bcc: string;
to: string[];
cc: string[];
bcc: string[];
receivedDate: Date;
subject: string;
parts: MessageEntitySummary[];
Expand Down
4 changes: 2 additions & 2 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/MessageSummary.ts
Expand Up @@ -2,7 +2,7 @@
constructor(
id: string,
from: string,
to: string,
to: string[],
receivedDate: Date,
subject: string,
attachmentCount: number,
Expand All @@ -21,7 +21,7 @@

id: string;
from: string;
to: string;
to: string[];
receivedDate: Date;
subject: string;
attachmentCount: number;
Expand Down
Expand Up @@ -42,7 +42,7 @@ export default class MessagesController {

// post: api/Messages/${encodeURIComponent(id)}
public markMessageRead_url(id: string): string {
return `${this.apiBaseUrl}/${encodeURIComponent(id)}`;
return `${this.apiBaseUrl}/${encodeURIComponent(id)}/markRead`;
}

public async markMessageRead(id: string): Promise<void> {
Expand Down
15 changes: 15 additions & 0 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/VersionController.ts
@@ -0,0 +1,15 @@
import axios from "axios";
import VersionInfo from "./VersionInfo";

export default class VersionController {
constructor() {}

public getVersion_url(): string {
return `api/Version`;
}

public async getVersion(): Promise<VersionInfo> {
return (await axios.get(this.getVersion_url(), null || undefined))
.data as VersionInfo;
}
}
@@ -1,4 +1,4 @@
export default class Info {
export default class VersionInfo {

constructor(version: string, infoVersion: string) {

Expand Down

0 comments on commit 0337655

Please sign in to comment.