/// <summary> /// 事务超时计算函数 /// </summary> protected virtual void TimerElapsed() { if (_transactions.Count == 0) { return; } IList <TransactionIdentity> expireValues = new List <TransactionIdentity>(); //check dead flag for transaction. foreach (KeyValuePair <TransactionIdentity, IMessageTransaction <TMessage> > pair in _transactions) { if (pair.Value.GetLease().IsDead) { expireValues.Add(pair.Key); } } if (expireValues.Count == 0) { return; } //remove expired transactions. foreach (TransactionIdentity expireValue in expireValues) { IMessageTransaction <TMessage> transaction = GetRemove(expireValue); if (transaction != null) { ((MessageTransaction <TMessage>)transaction).SetTimeout(); TransactionExpiredHandler(new LightSingleArgEventArgs <IMessageTransaction <TMessage> >(transaction)); } } }
public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; var message = MimeKit.MimeMessage.Load(textMessage.Content); Console.WriteLine("New message from {0}: {1}", message.From, message.Subject); var email = new Email() { Body = message.HtmlBody, Cc = message.Cc.Cast <MailboxAddress>().Select(x => x.Address).ToList(), From = message.From.ToString(), HadAttachments = message.Attachments.Any(), Subject = message.Subject, To = message.To.Cast <MailboxAddress>().Select(x => x.Address).ToList(), ReceivedAt = DateTimeOffset.UtcNow, }; _messages.Add(email); TrimStorage(); return(Task.FromResult(SmtpResponse.Ok)); }
public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var id = Guid.NewGuid().ToString("n"); var receivedOn = DateTime.Now; var textMessage = (ITextMessage)transaction.Message; var message = MimeMessage.Load(textMessage.Content); var model = new MessageModel() { Id = id, From = GetFromAddress(message), To = message.To.ToString(), Subject = message.Subject, HtmlBody = message.HtmlBody, TextBody = message.TextBody, Attachments = GetAttachments(message), ReceivedOn = receivedOn }; MessageManager.AddMessage(model); return(Task.FromResult(SmtpResponse.Ok)); }
/// <summary> /// Save the given message to the underlying storage system. /// </summary> /// <param name="context">The session context.</param> /// <param name="transaction">The SMTP message transaction to store.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The response code to return that indicates the result of the message being saved.</returns> public override Task <SmtpResponse> SaveAsync( ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { return(Task.FromResult(_delegate(context, transaction))); }
/// <inheritdoc /> public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; var message = MimeMessage.Load(textMessage.Content); foreach (var sender in message.From) { foreach (var recipient in message.To) { if (!(sender is MailboxAddress senderEmail) || !(recipient is MailboxAddress recipientEmail)) { continue; } try { var acmeMessage = MimeKitConverter.ConvertToMessage(senderEmail, recipientEmail, message); Log.Info($"INCOMING FROM {senderEmail.Address} TO {recipientEmail.Address} : {message.Subject}"); this.MessageReceived?.Invoke(this, acmeMessage); } catch (Exception e) { Log.Error(e); } } } return(Task.FromResult(SmtpResponse.Ok)); }
public override async Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { try { var textMessage = (ITextMessage)transaction.Message; var message = MimeMessage.Load(textMessage.Content); var entity = message.ToReceivedMail(); var mailGuid = entity.Headers.ContainsKey(MailGuidHeader) ? entity.Headers[MailGuidHeader] : Guid.NewGuid().ToString(); foreach (var mimeEntity in message.Attachments) { /* TODO store attachements as tmp files and load them to minio */ } _backgroundJobClient.Enqueue <RedisMinioStoreJob>(rmsj => rmsj.StoreMail(transaction.To.Select(im => im.AsAddress()).ToList(), mailGuid, entity)); return(SmtpResponse.Ok); } catch (Exception e) { Console.WriteLine(e); return(SmtpResponse.MailboxUnavailable); } }
public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; var message = MimeKit.MimeMessage.Load(textMessage.Content); Log.Logs.Instance.Push($"[Mail Server] Mail received. from='{message.From}', to='{message.To}', title='{message.Subject}'"); var mailbox_path = Path.Combine(AppProvider.ApplicationPath, "mailbox"); if (!Directory.Exists(mailbox_path)) { Directory.CreateDirectory(mailbox_path); } var save_path = Path.Combine(mailbox_path, $"{DateTime.Now.Ticks}-{(message.Subject + Crypto.Random.RandomString(15)).GetHashMD5()}.mime"); File.WriteAllText(save_path, message.ToString()); DataBase.Add(new MailColumnModel { Title = message.Subject, DateTime = message.Date.UtcDateTime.Ticks.ToString(), From = message.From.ToString(), To = message.To.ToString(), FileName = save_path, }); return(Task.FromResult(SmtpResponse.Ok)); }
public async Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken stoppingToken) { try { _logger.LogInformation($"Using stack {_stack.Name}."); MimeMessage message; using (var stream = ((ITextMessage)transaction.Message).Content) { message = MimeMessage.Load(stream); } AddBccEmails(message, transaction); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var middleware in _stack.Middlewares) { message = await middleware.RunAsync(message, context, transaction, stoppingToken).ConfigureAwait(false); } } catch (Exception exception) { _logger.Log(LogLevel.Error, "Email middleware routing failed"); return(new SmtpResponse(SmtpReplyCode.TransactionFailed, exception.Message)); } return(SmtpResponse.Ok); }
public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; MimeMessage message = MimeKit.MimeMessage.Load(textMessage.Content); _buffer.Add(message); return(Task.FromResult(SmtpResponse.Ok)); }
public MockMessage(IMessageTransaction transaction, ReadOnlySequence <byte> buffer) { Transaction = transaction; using var stream = new MemoryStream(buffer.ToArray()); MimeMessage = MimeMessage.Load(stream); }
public MessageTransactionDecorator( IMessageTransaction source, IOutboundTransport outbound, InboundTransportOptions options) { this.source = source; this.outbound = outbound; this.options = options; }
public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; var message = MimeMessage.Load(textMessage.Content); Messages.Add(message); _semaphore.Release(); return(Task.FromResult(SmtpResponse.Ok)); }
public override async Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var statusUser = Config.GetSection("StatusUser").Value; var alarmUser = Config.GetSection("AlarmUser").Value; var textMessage = (ITextMessage)transaction.Message; var message = MimeMessage.Load(textMessage.Content); var user = transaction.To.First().User; // // Send SMS in alert event only // if (user.Equals(alarmUser, StringComparison.InvariantCultureIgnoreCase)) { Logger.LogInformation("Received alarm event"); var apiKey = Guid.Parse(Config.GetSection("ApiKey").Value); var from = Config.GetSection("From").Value; var recipients = Config.GetSection("Recipients").GetChildren().Select(e => e.Value).ToList(); Logger.LogInformation( $"Will send alarm SMS to the following recipients: {string.Join(", ", recipients)}"); var client = new TextClient(apiKey); var result = await client .SendMessageAsync(message.TextBody, from, recipients, transaction.From.User, cancellationToken) .ConfigureAwait(false); if (result.statusCode == TextClientStatusCode.Ok) { Logger.LogInformation($"Successfully sent the following message to recipients: {message.TextBody}"); return(await Task.FromResult(SmtpResponse.Ok)); } Logger.LogError($"Message delivery failed: {result.statusMessage} ({result.statusCode})"); return(await Task.FromResult(SmtpResponse.TransactionFailed)); } if (user.Equals(statusUser, StringComparison.InvariantCultureIgnoreCase)) { Logger.LogInformation($"Received status change: {message.TextBody}"); } else { Logger.LogWarning($"Unknown message received (maybe a test?): {message.TextBody}"); } return(await Task.FromResult(SmtpResponse.Ok)); }
public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = ( ITextMessage )transaction.Message; var message = MimeKit.MimeMessage.Load(textMessage.Content); actualEmails.Push(message.HtmlBody); return(Task.FromResult(SmtpResponse.Ok)); }
private static string GetReceivedBody(IMessageTransaction receivedMessage) { if (receivedMessage.Message is ITextMessage textMessage) { var streamReader = new StreamReader(textMessage.Content); return(streamReader.ReadToEnd()); } throw new NotSupportedException("only ITextMessage supported"); }
public override async Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; var message = MimeKit.MimeMessage.Load(textMessage.Content); queueService.Push(QueuedEmailMessage.FromMimeMessage(message)); return(SmtpResponse.Ok); }
/// <summary> /// 激活一个事务,并尝试处理该事务的响应消息流程 /// </summary> /// <param name="identity">事务唯一标示</param> /// <param name="response">响应消息</param> public void Active(TransactionIdentity identity, TMessage response) { IMessageTransaction <TMessage> transaction = GetRemove(identity); if (transaction == null) { return; } transaction.SetResponse(response); }
/// <summary> /// 为一个管理中的事务进行续约操作 /// </summary> /// <param name="key">事务唯一键值</param> /// <param name="timeSpan">续约时间</param> /// <returns> /// 返回续约后的时间 /// <para>* 如果返回值 = MIN(DateTime), 则表示续约失败</para> /// </returns> public virtual DateTime Renew(TransactionIdentity key, TimeSpan timeSpan) { IMessageTransaction <TMessage> transaction = GetTransaction(key); if (transaction == null) { return(DateTime.MinValue); } return(transaction.GetLease().Renew(timeSpan)); }
/// <summary> /// Save the given message to the underlying storage system. /// </summary> /// <param name="context">The session context.</param> /// <param name="transaction">The SMTP message transaction to store.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A unique identifier that represents this message in the underlying message store.</returns> public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; using (var reader = new StreamReader(textMessage.Content, Encoding.UTF8)) { Console.WriteLine("Hello Data" + reader.ReadToEnd()); } return(Task.FromResult(SmtpResponse.Ok)); }
public override async Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var message = MimeMessage.Load(((ITextMessage)transaction.Message).Content); await _bot.SendTextMessageAsync( chatId : _chatId, text : $"{message.Subject}\nFrom: {message.From}\nTo: {message.To}\n{message.TextBody}", cancellationToken : cancellationToken); return(SmtpResponse.Ok); }
public override Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, ReadOnlySequence <byte> buffer, CancellationToken cancellationToken) { var scope = (IServiceScope)context.Properties[SmtpServerConstants.Scope]; var logger = scope.ServiceProvider.GetRequiredService <ILogger <MailDamMessageStore> >(); Guid sessionId = (Guid)context.Properties[SmtpServerConstants.SessionId]; var mailboxId = (Guid)context.Properties[SmtpServerConstants.Mailbox]; var mailId = Guid.NewGuid(); var mailboxRepository = scope.ServiceProvider.GetService <IMailboxRepository>(); var mailbox = mailboxRepository.Get(mailboxId, false); var mailRepository = scope.ServiceProvider.GetService <IMailRepository>(); using var messageStream = new MemoryStream(); var position = buffer.GetPosition(0); while (buffer.TryGet(ref position, out var memory)) { messageStream.Write(memory.Span); } messageStream.Position = 0; var message = MimeKit.MimeMessage.LoadAsync(messageStream, cancellationToken).Result; bool result = true; if (mailbox.ImapEnabled && message != null) { try { Imap.SendMessageToImap(mailbox, message); logger.LogInformation($"Storing mail {mailId} in session {sessionId} for mailbox {mailbox.MailboxId} in imap"); } catch (Exception e) { logger.LogError(e, $"Storing of mail failed with in session {sessionId} for mailbox {mailbox.MailboxId} in imap because: {e.Message}"); result = false; } } if (!mailbox.Passthrough && message != null) { result = result && SaveMessage(logger, mailRepository, messageStream, mailId, message, mailboxId, sessionId); } return(result ? Task.FromResult(SmtpResponse.Ok) : Task.FromResult(SmtpResponse.TransactionFailed)); }
/// <summary> /// Return the MIME content of the text message. /// </summary> /// <param name="messageTransaction">The message transaction to return the message text body from.</param> /// <returns>The MIME content of the text message.</returns> public static string Mime(this IMessageTransaction messageTransaction) { if (messageTransaction == null) { throw new ArgumentNullException(nameof(messageTransaction)); } var textMessage = (ITextMessage)messageTransaction.Message; return(textMessage.Mime()); }
public override async Task <SmtpResponse> SaveAsync( ISessionContext context, IMessageTransaction transaction, ReadOnlySequence <byte> buffer, CancellationToken cancellationToken) { await this._receivedDataHandler.HandleReceivedAsync( buffer.ToArray(), transaction.To.Select(s => s.AsAddress()).ToArray()); return(SmtpResponse.Ok); }
public override async Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, ReadOnlySequence <byte> buffer, CancellationToken cancellationToken) { var stream = new MemoryStream(buffer.ToArray(), writable: false); var message = await MimeMessage.LoadAsync(stream, cancellationToken); await _bot.SendTextMessageAsync( chatId : _chatId, text : $"{message.Subject}\nFrom: {message.From}\nTo: {message.To}\n{message.TextBody}", cancellationToken : cancellationToken); return(SmtpResponse.Ok); }
/// <summary> /// Returns the subject from the message. /// </summary> /// <param name="messageTransaction">The message transaction to return the message subject from.</param> /// <returns>The message subject from the message transaction.</returns> public static string Subject(this IMessageTransaction messageTransaction) { if (messageTransaction == null) { throw new ArgumentNullException(nameof(messageTransaction)); } var textMessage = (ITextMessage)messageTransaction.Message; textMessage.Content.Position = 0; return(MimeKit.MimeMessage.Load(textMessage.Content).Subject); }
public override async Task <SmtpResponse> SaveAsync( ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { var textMessage = (ITextMessage)transaction.Message; this._receivedDataHandler.HandleReceived( await ToArrayAsync(textMessage.Content), transaction.To.Select(s => s.AsAddress()).ToArray()); return(SmtpResponse.Ok); }
SaveAsync(ISessionContext context, IMessageTransaction transaction, CancellationToken cancellationToken) { ITextMessage textMessage = (ITextMessage)transaction.Message; using (var reader = new StreamReader(textMessage.Content, Encoding.UTF8)) { Message.Invoke(reader.ReadToEnd()); } return(Task.FromResult(SmtpResponse.Ok)); }
/* * BCC recipients are not part of the MIME message so they are not added to * the MimeMessage. See: https://github.com/cosullivan/SmtpServer/issues/35 * To solve this problem, we add all transaction emails that are not part of * the MIME message to the BCC. */ private void AddBccEmails(MimeMessage message, IMessageTransaction transaction) { var messageEmails = FlattenInternetAddresses(message.To.Union(message.Cc)) .Select(ma => ma.Address.ToLower()); var transactionEmails = transaction.To .Select(m => m.AsAddress().ToLower()) .Distinct(); var bccMailboxAddresses = transactionEmails.Except(messageEmails) .Select(s => new MailboxAddress(s)); message.Bcc.AddRange(bccMailboxAddresses); }
public override async Task <SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, ReadOnlySequence <byte> buffer, CancellationToken cancellationToken) { logger.LogInformation("Mail.Receive :: begin"); try { using var scope = serviceScopeFactory.CreateScope(); await using var stream = new MemoryStream(); var position = buffer.GetPosition(0); while (buffer.TryGet(ref position, out var memory)) { await stream.WriteAsync(memory, cancellationToken); } stream.Position = 0; var message = await MimeMessage.LoadAsync(stream, cancellationToken); logger.LogInformation($"Mail.Receive :: subject:{message.Subject}, sender:{message.From}"); bool saved = false; if (message.Subject.Equals("motion", StringComparison.OrdinalIgnoreCase)) { string sourceId = message.From.FirstOrDefault().ToString(); sourceId = sourceId.Substring(0, sourceId.IndexOf("@")); var device = jsonDatabaseService.Cameras.FirstOrDefault(c => c.SourceID == sourceId); if (device != null) { await scope.ServiceProvider.GetService <ITriggerService>().FireTriggersFromDevice(device, DeviceEvent.Motion); await SaveToEml(scope, message.MessageId, stream.ToArray(), device.Source.ToString(), device.SourceID); saved = true; } } if (!saved) { await SaveToEml(scope, message.MessageId, stream.ToArray(), "raw", "unknown"); } } catch (Exception ex) { logger.LogError(ex, "Mail.Receive :: unknown error"); } logger.LogInformation("Mail.Receive :: done"); return(SmtpResponse.Ok); }
/// <summary> /// Returns the text message body. /// </summary> /// <param name="messageTransaction">The message transaction to return the message text body from.</param> /// <param name="charset">The character set to use.</param> /// <returns>The message text body from the message transaction.</returns> public static string Text(this IMessageTransaction messageTransaction, string charset = "utf-8") { if (messageTransaction == null) { throw new ArgumentNullException(nameof(messageTransaction)); } var textMessage = (ITextMessage)messageTransaction.Message; textMessage.Content.Position = 0; var message = MimeKit.MimeMessage.Load(textMessage.Content); return(((TextPart)message.Body).GetText(charset).TrimEnd('\n', '\r')); }
private async Task ProcessTransaction(IMessageTransaction transaction) { Func<Task> completion; try { using (new DomainTransactionScope(transaction.Message.Id, transaction.RetryCount)) { // process message within a logical transaction that can be used for processing idempotency await this.messageDispatcher.ProcessMessage(transaction.Message); } completion = () => transaction.Commit(); } catch (Exception ex) { this.logger.Error(ex, "Failed to process message {0} with id {1}", transaction.Message.Name, transaction.Message.Id); completion = () => transaction.Fail(); } // try to complete the transaction, regardless of failures try { await completion(); } catch (Exception ex) { this.logger.Error(ex, "Failed to complete message {0} with id {1}", transaction.Message.Name, transaction.Message.Id); } }