public IEnumerable <string> ParseMailboxListHeader(IEnumerable <string> header) { return(header .SelectMany(h => h.SplitQuoted(',', '"', '\\', StringSplitOptions.None)) .Select(address => MailUtilities.GetMailboxFromAddress(address, _log)) .Where(m => !string.IsNullOrEmpty(m))); }
private Task <IWritable[]> CreateDispatchesAsync( string mailId, IEnumerable <string> recipients, string sender, CancellationToken token) { string senderDomain = MailUtilities.GetDomainFromMailbox(sender); return(Task.WhenAll( recipients .GroupBy(MailUtilities.GetDomainFromMailbox) .SelectMany( g => { if (_settings.Value.DomainName == g.Key) { _log.Information($"{mailId} is local mail found"); return g.Select(r => _delivery.NewMailAsync(mailId, r, token).Cast <IMailboxItemWriteReference, IWritable>()); } if (_settings.Value.RelayDomains.Any(d => string.Equals(d.Name, g.Key, StringComparison.OrdinalIgnoreCase)) || _settings.Value.DomainName == senderDomain) { _log.Information($"{mailId} is related to {g.Key}"); return _transfer.NewMailAsync(mailId, sender, g.ToImmutableList(), token) .Cast <IMailWriteReference, IWritable>() .ToEnumerable(); } _log.Error($"Invalid domain {g.Key}"); return Enumerable.Empty <Task <IWritable> >(); } ) )); }
public ISet <string> ExpandDistributionLists( string sender, IEnumerable <string> originalRecipients, HashSet <string> excludedFromExpansion) { var to = new HashSet <string>(); foreach (string recipient in originalRecipients) { DomainSettings domain = null; if (_domainSettings.TryGetValue( MailUtilities.GetDomainFromMailbox(recipient), out Lazy <IVolatile <DomainSettings> > settings)) { domain = settings.Value.Value; } DistributionList distributionList = domain?.DistributionLists?.FirstOrDefault(dl => dl.Mailbox == recipient); if (distributionList != null) { if (!CheckValidSender(sender, distributionList)) { _log.Warning($"Attempt by invalid sender {sender} to send to DL {distributionList.Mailbox}"); continue; } IEnumerable <string> nonExcludedMembers = distributionList.Members.Where(m => !excludedFromExpansion.Contains(m)); foreach (string member in nonExcludedMembers) { to.Add(member); } continue; } { // C# compiler mistake that prevents collapsing the domain.Alias null check if (domain?.Aliases != null && domain.Aliases.TryGetValue(recipient, out string newRecipient)) { if (excludedFromExpansion.Contains(newRecipient)) { continue; } to.Add(newRecipient); continue; } } to.Add(recipient); } return(to); }
public static bool CheckValidSender(string sender, DistributionList distributionList) { if (!distributionList.Enabled) { return(false); } if (!distributionList.AllowExternalSenders && MailUtilities.GetDomainFromMailbox(sender) != MailUtilities.GetDomainFromMailbox(distributionList.Mailbox)) { return(false); } return(true); }
private async Task DispatchSingleMailReferenceAsync( IMailReadReference readReference, Stream bodyStream, CancellationToken token) { string sender = readReference.Sender; IDictionary <string, IEnumerable <string> > headers = await MailUtilities.ParseHeadersAsync(bodyStream); ISet <string> recipients = AugmentRecipients(sender, readReference.Recipients, headers); if (!recipients.Any()) { _log.Warning($"{readReference.Id} had no recipients"); } (bodyStream, sender) = await ReplaceSenderAsync(headers, bodyStream, sender, token); IWritable[] dispatchReferences = await CreateDispatchesAsync( readReference.Id, recipients, sender, token); if (!dispatchReferences.Any()) { _log.Warning($"Failed to locate any processor for {readReference.Id}"); } using (var targetStream = new MultiStream(dispatchReferences.Select(r => r.BodyStream))) { await bodyStream.CopyToAsync(targetStream, token); } await Task.WhenAll(dispatchReferences.Select(r => r.Store.SaveAsync(r, token))); }