protected void ButtonPreview_Click(object sender, EventArgs e)
    {
        Person       currentPerson = Person.FromIdentity(Convert.ToInt32(HttpContext.Current.User.Identity.Name));
        Organization org           = Organization.FromIdentity(Convert.ToInt32(this.DropOrganizations.SelectedValue));
        Geography    geo           = Geography.FromIdentity(Convert.ToInt32(this.DropGeographies.SelectedValue));

        TypedMailTemplate template;

        if (this.DropRecipients.SelectedValue == "Members")
        {
            MemberMail membermail = new MemberMail();
            template                  = membermail;
            membermail.pSubject       = this.TextSubject.Text;
            membermail.pBodyContent   = this.RadEditorBody.Content;
            membermail.pOrgName       = org.MailPrefixInherited;
            membermail.pGeographyName = (geo.Identity == Geography.RootIdentity ? org.NameShort : geo.Name);
        }
        else
        {
            OfficerMail officermail = new OfficerMail();
            template                   = officermail;
            officermail.pSubject       = this.TextSubject.Text;
            officermail.pBodyContent   = this.RadEditorBody.Content;
            officermail.pOrgName       = org.MailPrefixInherited;
            officermail.pGeographyName = (geo.Identity == Geography.RootIdentity ? org.NameShort : geo.Name);
        }

        OutboundMail fake = template.CreateOutboundFake(currentPerson, org, geo);


        this.LiteralPreview.Text = fake.RenderHtml(currentPerson, org.DefaultCountry.Culture);
        this.RadEditorBody.Focus();
    }
Esempio n. 2
0
    private void CreatePreview()
    {
        Person       currentPerson = Person.FromIdentity(Convert.ToInt32(HttpContext.Current.User.Identity.Name));
        Organization org           = Organization.FromIdentity(Convert.ToInt32(this.DropOrganizations.SelectedValue));

        if (this.DropGeographies.SelectedIndex > -1)
        {
            Geography geo = Geography.FromIdentity(Convert.ToInt32(this.DropGeographies.SelectedValue));

            WelcomeMail welcomemail = new WelcomeMail();
            welcomemail.pSubject     = this.TextSubject.Text;
            welcomemail.pBodyContent = this.TextBody.Text;
            welcomemail.pOrgName     = org.MailPrefixInherited;

            welcomemail.pGeographyName = "";
            if (geo.Identity != Geography.RootIdentity)
            {
                welcomemail.pGeographyName = geo.Name;
            }

            OutboundMail fake = welcomemail.CreateOutboundFake(currentPerson, org, geo);
            this.LiteralPreview.Text = fake.RenderHtml(currentPerson, org.DefaultCountry.Culture);
        }

        this.TextBody.Focus();
    }
Esempio n. 3
0
        public void SendNotice(TypedMailTemplate mailtempl, int organizationId, bool asOfficer)
        {
            OutboundMail mail = mailtempl.CreateFunctionalOutboundMail(
                asOfficer ? MailAuthorType.PirateWeb : MailAuthorType.Service,
                OutboundMail.PriorityNormal, Organization.FromIdentity(organizationId),
                Geography.Root, DateTime.Now);

            mail.AddRecipient(this, asOfficer);
            mail.SetRecipientCount(1);
            mail.SetResolved();
            mail.SetReadyForPickup();
        }
Esempio n. 4
0
    protected void ButtonSend_Click(object sender, EventArgs e)
    {
        if (this.TextBody.Text.Length > 1)
        {
            ClientScript.RegisterStartupScript(this.GetType(), "StartupMessage", "alert('Your mail has been placed on the outbound queue. You will receive status reports in e-mail as the transmission progresses.');", true);

            Person       currentPerson = Person.FromIdentity(Convert.ToInt32(HttpContext.Current.User.Identity.Name));
            Organization org           = Organization.FromIdentity(Convert.ToInt32(this.DropOrganizations.SelectedValue));
            if (this.DropGeographies.SelectedIndex < 0)
            {
                return;
            }

            Geography geo = Geography.FromIdentity(Convert.ToInt32(this.DropGeographies.SelectedValue));

            TypedMailTemplate template;
            if (this.DropRecipients.SelectedValue == "Members")
            {
                MemberMail membermail = new MemberMail();
                template                  = membermail;
                membermail.pSubject       = this.TextSubject.Text;
                membermail.pBodyContent   = this.TextBody.Text;
                membermail.pOrgName       = org.MailPrefixInherited;
                membermail.pGeographyName = (geo.Identity == Geography.RootIdentity ? org.NameShort : geo.Name);
            }
            else
            {
                OfficerMail officermail = new OfficerMail();
                template                   = officermail;
                officermail.pSubject       = this.TextSubject.Text;
                officermail.pBodyContent   = this.TextBody.Text;
                officermail.pOrgName       = org.MailPrefixInherited;
                officermail.pGeographyName = (geo.Identity == Geography.RootIdentity ? org.NameShort : geo.Name);
            }

            OutboundMail mail = template.CreateOutboundMail(currentPerson, OutboundMail.PriorityNormal, org, geo);

            // We're not resolving recipients here, but deferring that to PirateBot after pickup
            mail.SetReadyForPickup();
        }
        else
        {
            ClientScript.RegisterStartupScript(this.GetType(), "StartupMessage", "alert('Nothing to do, the mail is empty...');", true);
        }
    }
Esempio n. 5
0
    protected void ButtonTest_Click(object sender, EventArgs e)
    {
        int actingOrgId = (int)ViewState["actingOrg"];

        if (actingOrgId == 0)
        {
            ErrorMsg.Text = "No organisation!";
            return;
        }
        Geography    geography = this.GeographyTree.SelectedGeography;
        Organization actingOrg = Organization.FromIdentity(actingOrgId);

        if (this.CheckSms.Checked)
        {
            string smsText = this.TextSms.Text;
            if (!string.IsNullOrEmpty(smsText) && smsText.Trim().Length > 3) // 3 characters is too small message, should always be more
            {
                _currentUser.SendPhoneMessage("PP: " + smsText.Trim());

                ChargeBudget(SelectBudget(geography), PhoneMessageTransmitter.SMSCost, "Test SMS");
            }
        }

        if (this.CheckMail.Checked)
        {
            ActivistMail activistMail = new ActivistMail();

            activistMail.pSubject       = this.TextMailSubject.Text;
            activistMail.pBodyContent   = this.TextMailBody.Text;
            activistMail.pOrgName       = actingOrg.MailPrefixInherited;
            activistMail.pGeographyName = (geography.Identity == Geography.RootIdentity ? "" : geography.Name);

            OutboundMail mail = activistMail.CreateFunctionalOutboundMail(MailAuthorType.ActivistService, OutboundMail.PriorityNormal, actingOrg, geography);

            mail.AddRecipient(_currentUser, false);
            mail.SetRecipientCount(1);
            mail.SetResolved();
            mail.SetReadyForPickup();
        }
        PanelTestSent.Visible = true;
    }
Esempio n. 6
0
 public bool CreateOutboundMail(OutboundMail mail)
 {
     return(this.Post(API_FRESHDESK_OUTBOUND_EMAIL, mail.ToJson()));
 }
Esempio n. 7
0
        private static void CheckOneFeed(string readerUrl, string persistAsKey, int orgIdForTemplate)
        {
            string persistenceKey = String.Format("Pressrelease-Highwater-{0}", persistAsKey);

            DateTime highWaterMark = DateTime.MinValue;

            RssReader reader = null;

            try
            {
                string highWaterMarkString = Persistence.Key[persistenceKey];

                if (string.IsNullOrEmpty(highWaterMarkString))
                {
                    //Initialize highwatermark if never used
                    highWaterMark = DateTime.Now;
                    Persistence.Key[persistenceKey] = DateTime.Now.ToString();
                }
                else
                {
                    try
                    {
                        highWaterMark = DateTime.Parse(highWaterMarkString);
                    }
                    catch (Exception ex)
                    {
                        HeartBeater.Instance.SuggestRestart();
                        throw new Exception(
                                  "Triggered restart. Unable to read/parse old highwater mark from database in PressReleaseChecker.Run(), from key:" +
                                  persistenceKey + ", loaded string was '" + highWaterMarkString + "' expected format is " +
                                  DateTime.Now, ex);
                    }
                }
                DateTime storedHighWaterMark = highWaterMark;
                reader = new RssReader(readerUrl);
                Rss rss = reader.Read();

                foreach (RssChannelItem item in rss.Channel.Items)
                {
                    // Ignore any items older than the highwater mark.
                    // Also ignore if older than two days

                    if (item.PubDate < highWaterMark || item.PubDate < DateTime.Now.AddDays(-2))
                    {
                        continue;
                    }

                    // This is an item we should publish.

                    // Set highwater datetime mark. We do this first, BEFORE processing, as a defense against mail floods,
                    // if should something go wrong and unexpected exceptions happen.

                    // We used to add 70 minutes as a defense against mistakes on DST switch in spring and fall (yes, it has happened), but have reduced to two.

                    if (item.PubDate > storedHighWaterMark)
                    {
                        Persistence.Key[persistenceKey] = item.PubDate.AddMinutes(2).ToString();
                        storedHighWaterMark             = item.PubDate.AddMinutes(2);

                        // Verify that it was written correctly to database. This is defensive programming to avoid a mail flood,
                        // in case we can't write to the database for some reason.
                        string newStoredHighWaterString = "";
                        try
                        {
                            newStoredHighWaterString = Persistence.Key[persistenceKey];
                            DateTime temp = DateTime.Parse(newStoredHighWaterString);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception(
                                      "Unable to commit/parse new highwater mark to database in PressReleaseChecker.Run(), loaded string was '" +
                                      newStoredHighWaterString + "'", ex);
                        }

                        if (DateTime.Parse(Persistence.Key[persistenceKey]) < item.PubDate)
                        {
                            throw new Exception(
                                      "Unable to commit new highwater mark to database in PressReleaseChecker.Run()");
                        }
                    }

                    bool            allReporters  = false;
                    bool            international = false;
                    MediaCategories categories    = new MediaCategories();

                    foreach (RssCategory category in item.Categories)
                    {
                        if (category.Name == "Alla")
                        {
                            allReporters = true;
                        }
                        else if (category.Name == "Uncategorized")
                        {
                        }
                        else
                        {
                            try
                            {
                                MediaCategory mediaCategory = MediaCategory.FromName(category.Name);
                                categories.Add(mediaCategory);

                                if (category.Name.StartsWith("International"))
                                {
                                    international = true;
                                }
                            }
                            catch (Exception)
                            {
                                ExceptionMail.Send(
                                    new Exception("Unrecognized media category in press release: " + category.Name));
                            }
                        }
                    }

                    string mailText = Blog2Mail(item.Content);

                    // Create recipient list of relevant reporters

                    Reporters reporters = null;

                    if (allReporters)
                    {
                        reporters = Reporters.GetAll();
                    }
                    else
                    {
                        reporters = Reporters.FromMediaCategories(categories);
                    }

                    // Add officers if not int'l

                    People officers = new People();
                    Dictionary <int, bool> officerLookup = new Dictionary <int, bool>();

                    if (!international)
                    {
                        int[] officerIds = Roles.GetAllDownwardRoles(1, 1);
                        foreach (int officerId in officerIds)
                        {
                            officerLookup[officerId] = true;
                        }
                    }
                    else
                    {
                        officerLookup[1] = true;
                    }


                    // Send press release

                    //TODO: hardcoded  geo ... using  World
                    Organization     org = Organization.FromIdentity(orgIdForTemplate);
                    Geography        geo = Geography.Root;
                    PressReleaseMail pressreleasemail = new PressReleaseMail();

                    pressreleasemail.pSubject     = item.Title;
                    pressreleasemail.pDate        = DateTime.Now;
                    pressreleasemail.pBodyContent = Blog2Mail(item.Content);
                    pressreleasemail.pOrgName     = org.MailPrefixInherited;
                    if (allReporters)
                    {
                        pressreleasemail.pPostedToCategories = "Alla"; // TODO: TRANSLATE
                    }
                    else if (international)
                    {
                        pressreleasemail.pPostedToCategories = "International/English"; // TODO: THIS IS HARDCODED
                    }
                    else
                    {
                        pressreleasemail.pPostedToCategories =
                            PressReleaseMail.GetConcatenatedCategoryString(categories);
                    }

                    OutboundMail newMail = pressreleasemail.CreateFunctionalOutboundMail(MailAuthorType.PressService,
                                                                                         OutboundMail.PriorityHighest, org, geo);

                    int recipientCount = 0;
                    foreach (Reporter recipient in reporters)
                    {
                        if (!Formatting.ValidateEmailFormat(recipient.Email))
                        {
                            continue;
                        }
                        ++recipientCount;
                        newMail.AddRecipient(recipient);
                    }
                    foreach (int key in officerLookup.Keys)
                    {
                        Person recipient = Person.FromIdentity(key);
                        if (!Formatting.ValidateEmailFormat(recipient.Mail))
                        {
                            continue;
                        }
                        ++recipientCount;
                        newMail.AddRecipient(recipient, true);
                    }

                    newMail.SetRecipientCount(recipientCount);
                    newMail.SetResolved();
                    newMail.SetReadyForPickup();
                }
            }
            catch (Exception ex)
            {
                ExceptionMail.Send(
                    new Exception("PressReleaseChecker failed:" + ex.Message + "\r\nwhen checking " + readerUrl, ex));
            }
            finally
            {
                reader.Close();
            }
        }
Esempio n. 8
0
        public static string CreateWelcomeMail(Person person, Organization organization)
        {
            // for this person, iterate over all applicable geographies and organizations

            Organizations orgLine = organization.GetLine();
            Geographies   geoLine = person.Geography.GetLine();

            orgLine.Reverse(); // Start at the most local org

            Dictionary <int, bool> orgMailedLookup = new Dictionary <int, bool>();

            int    delay  = 0;
            string result = string.Empty;
            Random random = new Random();

            foreach (Organization org in orgLine)
            {
                foreach (Geography geo in geoLine) // but at the top geography
                {
                    AutoMail autoMail = AutoMail.FromTypeOrganizationAndGeography(AutoMailType.Welcome, org, geo);

                    if (autoMail == null)
                    {
                        continue;
                    }

                    Person lead    = null;
                    string geoName = geo.Name;

                    try
                    {
                        lead = Roles.GetLocalLead(org, geo);
                        orgMailedLookup[org.Identity] = true;
                        // Make sure that the chairman doesn't mail at a lower level
                    }
                    catch (ArgumentException)
                    {
                    }

                    if (lead == null && !orgMailedLookup.ContainsKey(org.Identity))
                    {
                        // If we get here, there is a mail template at the highest possible geo for this org, but no local lead.
                        // That's usually the case with board-centric organizations rather than executive-centric.
                        // Try to mail from chairman rather than the local lead.

                        try
                        {
                            orgMailedLookup[org.Identity] = true;
                            lead    = Roles.GetChairman(org);
                            geoName = "Chairman";
                        }
                        catch (ArgumentException)
                        {
                        }
                    }

                    if (lead == null)
                    {
                        // ok, give up if there isn't a chairman either or if we've already mailed this org from the chairman
                        continue;
                    }

                    // TODO: fetch lead from roles
                    WelcomeMail welcomemail = new WelcomeMail();

                    welcomemail.pOrgName = org.MailPrefixInherited;

                    welcomemail.pGeographyName = "";
                    if (geo.Identity != Geography.RootIdentity)
                    {
                        welcomemail.pGeographyName = geo.Name;
                    }

                    welcomemail.pBodyContent = autoMail.Body;
                    welcomemail.pSubject     = autoMail.Title;

                    OutboundMail newMail = welcomemail.CreateOutboundMail(lead, OutboundMail.PriorityNormal,
                                                                          org, geo, DateTime.Now.AddMinutes(delay));
                    newMail.AddRecipient(person.Identity, false);
                    newMail.SetRecipientCount(1);
                    newMail.SetResolved();
                    newMail.SetReadyForPickup();

                    result += String.Format(" - {0}/{1} by {2} (",
                                            org.NameShort, geoName, lead.Canonical);
                    if (delay == 0)
                    {
                        result += "sent now";
                        delay  += 37;
                    }
                    else
                    {
                        result += "sending at " + DateTime.Now.AddMinutes(delay).ToString("HH:mm");
                        delay  += 31 + random.Next(52);
                    }
                    result += ")\r\n";
                }
            }

            if (result.Length < 4)
            {
                result = "none\r\n";
            }

            return(result);
        }
Esempio n. 9
0
        public static void Run()
        {
            OutboundMail mail = OutboundMail.GetFirstUnresolved();

            if (mail == null)
            {
                return; // No unresolved -- nothing to do
            }

            // Use a dictionary to add people

            int downwardCount = 0;
            int upwardCount   = 0;

            Dictionary <int, bool> officerIds = new Dictionary <int, bool>();
            Dictionary <int, bool> personIds  = new Dictionary <int, bool>();

            // Add the affected people

            switch (mail.MailType)
            {
            case (int)TypedMailTemplate.TemplateType.MemberMail:
                // All members at this org and geography

                People people = People.FromOrganizationAndGeography(mail.Organization, mail.Geography);
                downwardCount = people.Count;
                foreach (Person person in people)
                {
                    personIds[person.Identity] = true;
                }
                break;

            case (int)TypedMailTemplate.TemplateType.OfficerMail:
                // All officers at this org and geography
                int[] officers = Roles.GetAllDownwardRoles(mail.OrganizationId, mail.GeographyId);
                downwardCount = officers.Length;
                foreach (int personId in officers)
                {
                    officerIds[personId] = true;
                }
                break;

            default:
                throw new InvalidOperationException("Unhandled mail mode; can't resolve mail id " +
                                                    mail.Identity);
            }

            int[] upwardIds = Roles.GetAllUpwardRoles(mail.OrganizationId, mail.GeographyId);
            upwardCount = upwardIds.Length;

            foreach (int personId in upwardIds)
            {
                // Filter for subscription of copies to local mail. Inefficient filter, room for optimization.

                if (Person.FromIdentity(personId).IsSubscribing(NewsletterFeed.TypeID.OfficerUpwardCopies))
                {
                    officerIds[personId] = true;
                }
            }

            // Assemble arrays

            List <int> officerIdList = new List <int>();

            foreach (int officerId in officerIds.Keys)
            {
                officerIdList.Add(officerId);
                if (personIds.ContainsKey(officerId))
                {
                    // If somebody is going to recieve this mail both due to area coverage and
                    // chain of command, send as chain of command only

                    personIds.Remove(officerId);
                }
            }

            List <int> personIdList = new List <int>();

            foreach (int personId in personIds.Keys)
            {
                personIdList.Add(personId);
            }

            // Check for people who have declined local mail

            Dictionary <int, bool> decliners = new Dictionary <int, bool>();

            int declineCount = decliners.Count;

            if (declineCount > 0)
            {
                foreach (int personId in decliners.Keys)
                {
                    personIds.Remove(personId);
                }

                // Rebuild list after decliners gone

                personIdList = new List <int>();
                foreach (int personId in personIds.Keys)
                {
                    personIdList.Add(personId);
                }
            }

            // TODO: Get queue count to give a time estimate until transmission


            // Create recipients

            mail.AddRecipients(personIdList.ToArray(), false);
            mail.AddRecipients(officerIdList.ToArray(), true);

            int countTotal = personIdList.Count + officerIdList.Count;

            // Mark as ready

            mail.SetRecipientCount(countTotal);
            mail.SetResolved();

            // TODO: Set recipient count of mail

            // Create a mail to the author

            string mailBody = "Your outbound mail with the title \"" + mail.Title +
                              "\" has been resolved for recipients and " +
                              "will be sent to " + countTotal.ToString("#,##0") + " people.\r\n\r\nOut of these " +
                              countTotal.ToString("#,##0") + ", " + (downwardCount - declineCount).ToString("#,##0") +
                              " are people within the requested " +
                              "organization/geography (" + Organization.FromIdentity(mail.OrganizationId).Name + "/" +
                              Geography.FromIdentity(mail.GeographyId).Name + "), and " +
                              upwardCount.ToString("#,##0") + " are people in the chain of command who are " +
                              "copied on the mail to know what's happening in the organization. There is normally some overlap between these two groups.\r\n\r\n";

            if (declineCount > 1)
            {
                mailBody += declineCount.ToString("#,##0") +
                            " people will not receive the message because they have declined local mail.\r\n\r\n";
            }
            else if (declineCount == 1)
            {
                mailBody += "One person will not receive the message because he or she has declined local mail.\r\n\r\n";
            }

            mailBody +=
                "Transmissions will begin " + (mail.ReleaseDateTime < DateTime.Now
                    ? "immediately"
                    : "in " + (mail.ReleaseDateTime - DateTime.Now).Minutes +
                                               " minutes") + ".\r\n";

            new MailTransmitter(
                "PirateWeb", "*****@*****.**",
                "Mail resolved: " + mail.Title + " (" + countTotal + " recipients)", mailBody,
                Person.FromIdentity(mail.AuthorPersonId), true).Send();
        }
Esempio n. 10
0
        internal static OutboundMailRecipient TransmitOneMail(OutboundMailRecipient recipient)
        {
            try
            {
                // If the mail address in illegal format, do not try to send anything:
                if (!Formatting.ValidateEmailFormat(recipient.EmailPerson.Email.Trim()))
                {
                    string msg = "Invalid email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                 "], mail [" +
                                 recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title;
                    throw new InvalidRecipientException(msg, null);
                }

                // If the mail address is marked as unreachable, do not try to send anything
                if (recipient.Person != null && recipient.Person.MailUnreachable)
                {
                    string msg = "MailUnreachable email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                 "], mail [" +
                                 recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title;
                    throw new InvalidRecipientException(msg, null);
                }

                // If the mail address is marked as unreachable, do not try to send anything
                if (recipient.Person != null && recipient.Person.NeverMail)
                {
                    string msg = "NeverMail email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                 "], mail [" +
                                 recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title;
                    throw new IgnoreRecipientException(msg, null);
                }


                // Otherwise, let's start processing

                OutboundMail mail = recipient.OutboundMail;

                bool     limitToLatin1   = false;
                bool     limitToText     = false;
                Encoding currentEncoding = Encoding.UTF8;

                string email = recipient.EmailPerson.Email.ToLower();


                if (mail.MailType == 0 || mail.TemplateName.EndsWith("Plain"))
                {
                    limitToText = true;
                }

                // TEST: Does this user require the use of a text-only message (as opposed to multipart/alternative)?
                if (recipient.Person != null && recipient.Person.LimitMailToText)
                {
                    limitToText = true;
                }

                // This is supposedly not a problem anymore
                //if (email.EndsWith("@hotmail.com") || email.EndsWith("@msn.com"))
                //{
                //    limitToLatin1 = true;
                //}

                // TEST: Does this user require the limited use of the Latin-1 charset (as opposed to Unicode?)
                if (recipient.Person != null && recipient.Person.LimitMailToLatin1)
                {
                    limitToLatin1 = true;
                }

                // Capability tests end here

                if (limitToLatin1)
                {
                    currentEncoding = Encoding.GetEncoding("ISO-8859-1");
                }
                else
                {
                    currentEncoding = Encoding.UTF8;
                }

                QuotedPrintable qp = QuotedPrintableEncoder[currentEncoding];


                MailMessage message = new MailMessage();

                if (mail.AuthorType == MailAuthorType.Person)
                {
                    try
                    {
                        message.From = new MailAddress(mail.Author.PartyEmail,
                                                       qp.EncodeMailHeaderString(mail.Author.Name + " (" + mail.Organization.MailPrefixInherited +
                                                                                 ")"),
                                                       currentEncoding);

                        if (mail.Author.Identity == 1)
                        {
                            //TODO: Create alternative party mail optional data field, or organization chairman (based on roles) differently
                            // Ugly hack
                            message.From = new MailAddress("*****@*****.**",
                                                           qp.EncodeMailHeaderString(mail.Author.Name + " (" +
                                                                                     mail.Organization.MailPrefixInherited + ")"),
                                                           currentEncoding);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidSenderException(
                                  "Invalid author address in MailProcessor.TransmitOneMail:" + (mail.AuthorPersonId) + ";" +
                                  mail.Author.PartyEmail, ex);
                    }
                }
                else
                {
                    try
                    {
                        FunctionalMail.AddressItem aItem =
                            mail.Organization.GetFunctionalMailAddressInh(mail.AuthorType);
                        message.From = new MailAddress(aItem.Email, qp.EncodeMailHeaderString(aItem.Name),
                                                       currentEncoding);
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidSenderException(
                                  "Unknown MailAuthorType in MailProcessor.TransmitOneMail:" + ((int)mail.AuthorType), ex);
                    }
                }


                if (recipient.AsOfficer && recipient.Person != null)
                {
                    try
                    {
                        message.To.Add(new MailAddress(recipient.Person.PartyEmail,
                                                       qp.EncodeMailHeaderString(recipient.Person.Name + " (" +
                                                                                 mail.Organization.MailPrefixInherited + ")"),
                                                       currentEncoding));
                    }
                    catch (FormatException e)
                    {
                        string msg = "Invalid officer email address:\r\nperson [" + recipient.Person.Identity +
                                     "], mail [" +
                                     recipient.Person.PartyEmail + "]\r\nwill not send mail:" +
                                     recipient.OutboundMail.Title;
                        throw new InvalidRecipientException(msg, e);
                    }
                }
                else
                {
                    try
                    {
                        message.To.Add(new MailAddress(recipient.EmailPerson.Email,
                                                       qp.EncodeMailHeaderString(recipient.EmailPerson.Name),
                                                       currentEncoding));
                    }
                    catch (FormatException e)
                    {
                        string msg = "Invalid email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity +
                                     "], mail [" +
                                     recipient.EmailPerson.Email + "]\r\nwill not send mail:" +
                                     recipient.OutboundMail.Title;
                        throw new InvalidRecipientException(msg, e);
                    }
                }

                string culture = mail.Organization.DefaultCountry.Culture;

                // UGLY UGLY UGLY HACK, NEEDS TO CHANGE ASAP:
                // We need to determine the culture of the recipient in order to use the right template. However, this is also dependent on the text body, which needs to be
                // in the same culture. At this point, we don't have the mail/recipient cultures in the schema. This would be the correct solution.

                // The INCORRECT but working solution is to do as we do here and check if a) it's a reporter and b) the reporter has International/English as a category. If so,
                // we change the culture to en-US. It's an ugly as all hell hack but it should work as a temporary stopgap.

                if (recipient.Reporter != null)
                {
                    MediaCategories categories = recipient.Reporter.MediaCategories;

                    foreach (MediaCategory category in categories)
                    {
                        if (category.Name == "International/English")
                        {
                            culture = Strings.InternationalCultureCode;
                            break;
                        }
                    }
                }

                if (limitToText)
                {
                    // if just text, then just add a plaintext body;
                    string text = "";

                    //Cant really see any reson the HtmlAgilityPack shouldn't be thread safe, but what the heck, just in case..
                    lock (lockObject)
                    {
                        try
                        {
                            text = mail.RenderText(recipient.EmailPerson, culture);
                        }
                        catch (Exception ex)
                        {
                            throw new RemoveRecipientException(
                                      "TextRendering failed for " + mail.Title + " to " + recipient.EmailPerson.Email +
                                      " will not retry.\n", ex);
                        }
                    }
                    message.BodyEncoding = currentEncoding;
                    message.Body         = text;
                }
                else
                {
                    // otherwise, add a multipart/alternative with text and HTML
                    string text = "";
                    string html = "";

                    //Cant really see any reson the HtmlAgilityPack shouldn't be thread safe, but what the heck, just in case..
                    Exception ex = null;
                    lock (lockObject)
                    {
                        try
                        {
                            text = mail.RenderText(recipient.EmailPerson, culture);
                            html = mail.RenderHtml(recipient.EmailPerson, culture);
                        }
                        catch (Exception e)
                        {
                            ex = e;
                        }
                    }
                    if (text == "")
                    {
                        throw new RemoveRecipientException(
                                  "Rendering (text) failed for " + mail.Title + " to " + recipient.EmailPerson.Email +
                                  " will not retry.\n", ex);
                    }
                    if (html == "" || ex != null)
                    {
                        throw new RemoveRecipientException(
                                  "Rendering (html) failed for " + mail.Title + " to " + recipient.EmailPerson.Email +
                                  " will not retry.\n", ex);
                    }

                    ContentType textContentType = new ContentType(MediaTypeNames.Text.Plain);
                    textContentType.CharSet = currentEncoding.BodyName;

                    ContentType htmlContentType = new ContentType(MediaTypeNames.Text.Html);
                    htmlContentType.CharSet = currentEncoding.BodyName;

                    AlternateView textView = null;
                    AlternateView htmlView = null;


                    if (limitToLatin1)
                    {
                        textView = new AlternateView(new MemoryStream(currentEncoding.GetBytes(text)),
                                                     textContentType);
                        htmlView = new AlternateView(new MemoryStream(currentEncoding.GetBytes(text)),
                                                     htmlContentType);
                    }
                    else
                    {
                        textView = AlternateView.CreateAlternateViewFromString(text, textContentType);
                        htmlView = AlternateView.CreateAlternateViewFromString(html, htmlContentType);
                    }

                    // A f*****g stupid Mono bug forces us to transfer-encode in base64: it can't encode qp properly
                    // (the "=" is not encoded to "=3D")

                    htmlView.TransferEncoding = TransferEncoding.Base64;
                    textView.TransferEncoding = TransferEncoding.Base64;

                    // Add the views in increasing order of preference

                    message.AlternateViews.Add(textView);
                    message.AlternateViews.Add(htmlView);
                }

                if (mail.AuthorType == MailAuthorType.PirateWeb)
                {
                    message.Subject = mail.Title;
                }
                else if (mail.MailType == 0)
                {
                    message.Subject = mail.Organization.MailPrefixInherited + ": " + mail.Title;
                }
                else
                {
                    //Title is set up in template processing in OutboundMail rendering.
                    message.Subject = mail.Title;
                }

                message.SubjectEncoding = currentEncoding;

                string smtpServer = ConfigurationManager.AppSettings["SmtpServer"];

                if (Debugger.IsAttached)
                {
                    Debug.WriteLine("sending " + message.Subject + " to " + recipient.EmailPerson.Email);
                    Thread.Sleep(200);  //simulate delay
                }


                if (smtpServer.ToLower() != "none")
                {
                    if (smtpServer == null || smtpServer.Length < 2)
                    {
                        smtpServer = "localhost";
                    }

                    try
                    {
                        SmtpClient client = new SmtpClient(smtpServer, 25);
                        client.Send(message);
                    }
                    catch (SmtpException e)
                    {
                        if (e.ToString().StartsWith("System.Net.Mail.SmtpException: 4"))
                        {
                            // Temporary error (SMTP 4xx). Try again.

                            Thread.Sleep(2000);  // Allow 2 seconds pause to wait for smtp-server to become available
                            throw new ReportAndRetryRecipientException("Temporary smtp error, will retry.", e);
                        }

                        // Otherwise, bad recipient (assume so). Have the mail removed from the queue.

                        List <string> recipients = new List <string>();
                        foreach (MailAddress address in message.To)
                        {
                            recipients.Add(address.Address);
                        }

                        ExceptionMail.Send(
                            new ArgumentException(
                                "Bad Recipients when sending to " + recipient.EmailPerson.Email + ": " +
                                String.Join(", ", recipients.ToArray()), e));

                        if (mail.AuthorType == MailAuthorType.Person)
                        {
                            try
                            {
                                mail.Author.SendOfficerNotice(
                                    "Failed recipient(s): " + String.Join(", ", recipients.ToArray()),
                                    "Some recipients failed inexplicably in a mail from you.", 1);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Failed to SendOfficerNotice to :" + mail.AuthorPersonId, ex);
                            }
                        }
                    }
                }
                return(recipient); // To pass this object onto the we're-done callback
            }
            catch (InvalidRecipientException ex)
            {
                throw ex;
            }
            catch (RetryRecipientException ex)
            {
                Thread.Sleep(2000);
                // Allow 2 seconds pause to avoid flooding the errorlog too fast in case of a permanent failure
                throw ex;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
Esempio n. 11
0
    public static void SendReminderMail(Person person, Memberships memberships)
    {
        // First, determine the organization template to use. Prioritize a long ancestry.

        // This is a hack for the Swedish structure.

        ReminderMail remindermail = new ReminderMail();


        int          longestAncestry  = 0; // "ancestry" as a length means distance to organization tree root
        int          shortestAncestry = 999;
        Organization topOrg           = null;
        Organization lowOrg           = null;
        DateTime     currentExpiry    = DateTime.MinValue;

        foreach (Membership membership in memberships)
        {
            if (membership.Organization.AutoAssignNewMembers)
            {
                Organizations ancestry = membership.Organization.GetLine();

                if (ancestry.Count > longestAncestry)
                {
                    longestAncestry       = ancestry.Count;
                    lowOrg                = membership.Organization;
                    remindermail.pOrgName = lowOrg.MailPrefixInherited;
                }

                if (ancestry.Count < shortestAncestry)
                {
                    shortestAncestry = ancestry.Count;
                    topOrg           = membership.Organization;
                }
            }
            if (membership.OrganizationId == Organization.PPSEid)
            {
                topOrg = membership.Organization;
                remindermail.pOrgName = membership.Organization.MailPrefixInherited;
                currentExpiry         = membership.Expires;
            }
        }

        DateTime newExpiry = currentExpiry;

        if (newExpiry < DateTime.Today.AddYears(10))
        {
            //do not mess with lifetime memberships
            newExpiry = newExpiry.AddYears(1);
            if (newExpiry > DateTime.Today.AddYears(1))
            {
                newExpiry = DateTime.Today.AddYears(1).AddDays(1);
            }
        }


        //Person sender = Person.FromIdentity(1); //Rick

        remindermail.pExpirationDate = currentExpiry;
        remindermail.pNextDate       = newExpiry;
        remindermail.pPreamble       = "<p> Vi är glada att du vill <strong>förnya ditt medlemskap</strong> i Piratpartiet och/eller Ung Pirat.<br /><br />Använd en av länkarna nedan så genomförs förnyelsen.<br />";

        string tokenBase = person.PasswordHash + "-" + currentExpiry.Year.ToString();

        Organization expectedLowOrg = Organizations.GetMostLocalOrganization(person.GeographyId, Organization.UPSEid);

        int ageThisYear = DateTime.Now.Year - person.Birthdate.Year;

        //Hardcoded: age = 26
        if (ageThisYear >= 26 && lowOrg.Inherits(Organization.UPSEid))
        {
            // If this person is older than 26, suggest that they leave UP.

            remindermail.pCurrentAge = ageThisYear.ToString();
            remindermail.pCurrentOrg = lowOrg.Name;
            remindermail.pOtherOrg   = topOrg.Name;
            string link = "https://pirateweb.net/Pages/Public/SE/People/MemberRenew.aspx?MemberId=" +
                          person.Identity.ToString() + "&Leave=" + lowOrg.Identity.ToString() +
                          "&SecHash=" + SHA1.Hash(tokenBase + "-Leave" + lowOrg.Identity.ToString()).
                          Replace(" ", "").Substring(0, 8);
            remindermail.pOtherRenewLink = link;
            remindermail.pWrongOrgSpan   = " "; //clear the other span
        }

        else if (lowOrg.Inherits(Organization.UPSEid) && lowOrg.Identity != expectedLowOrg.Identity)
        {
            // Is this person in the wrong locale?

            remindermail.pCurrentOrg    = lowOrg.Name;
            remindermail.pOtherOrg      = expectedLowOrg.Name;
            remindermail.pGeographyName = person.Geography.Name;
            //mailBody += "Du är medlem i " + lowOrg.Name + ", men när du bor i [b]" + person.Geography.Name +
            //             "[/b] så rekommenderar " +
            //             "vi att du byter till din lokala organisation, [b]" + expectedLowOrg.Name +
            //             "[/b]. Klicka här för att göra det:\r\n\r\n";

            string link = "https://pirateweb.net/Pages/Public/SE/People/MemberRenew.aspx?MemberId=" +
                          person.Identity.ToString() + "&Transfer=" + lowOrg.Identity.ToString() + "," +
                          expectedLowOrg.Identity.ToString() +
                          "&SecHash=" + SHA1.Hash(tokenBase + "-Transfer" + lowOrg.Identity.ToString() + "/" +
                                                  expectedLowOrg.Identity.ToString()).Replace(" ", "").Substring(0, 8);
            remindermail.pOtherRenewLink        = link;
            remindermail.pTooOldForYouthOrgSpan = " "; //clear the other span

            //mailBody += "[a href=\"" + link + "\"]" + link + "[/a]\r\n\r\n" +
            //            "Det är naturligtvis inget krav, utan du kan fortsätta precis som förut om du vill. " +
            //            "För att fortsätta i dina befintliga föreningar, klicka här:\r\n\r\n";
        }

        else
        {
            remindermail.pTooOldForYouthOrgSpan = " "; //clear the other span
            remindermail.pWrongOrgSpan          = " "; //clear the other span
        }

        string stdLink = "https://pirateweb.net/Pages/Public/SE/People/MemberRenew.aspx?MemberId=" +
                         person.Identity.ToString() +
                         "&SecHash=" + SHA1.Hash(tokenBase).Replace(" ", "").Substring(0, 8);

        remindermail.pStdRenewLink = stdLink;

        OutboundMail mail = remindermail.CreateFunctionalOutboundMail(MailAuthorType.MemberService, OutboundMail.PriorityNormal, topOrg, Geography.Root);

        if (mail.Body.Trim() == "")
        {
            throw new Exception("Failed to create a mailBody");
        }
        else
        {
            mail.AddRecipient(person.Identity, false);
            mail.SetRecipientCount(1);
            mail.SetResolved();
            mail.SetReadyForPickup();

            PWLog.Write(PWLogItem.Person, person.Identity, PWLogAction.MembershipRenewReminder, "Mail was sent to " + person.Email + " on request to renew membership.", string.Empty);
        }
    }
Esempio n. 12
0
        private static void CheckOneBlog(string readerFeedUrl, int personId)
        {
            try
            {
                Person sender = Person.FromIdentity(personId);

                string senderName    = sender.Name + " (Piratpartiet)";
                string senderAddress = sender.PartyEmail;


                if (personId == 5)
                {
                    senderName = "=?utf-8?Q?Christian_Engstr=C3=B6m_(Piratpartiet)?="; // compensate for Mono bug
                }
                if (personId == 1)
                {
                    senderAddress = "*****@*****.**";
                }

                RssReader reader     = new RssReader(readerFeedUrl);
                People    recipients = null;

                DateTime highWaterMark  = DateTime.MinValue;
                string   persistenceKey = "Newsletter-Highwater-" + personId.ToString();

                string highWaterMarkString = Persistence.Key[persistenceKey];

                try
                {
                    highWaterMark = DateTime.Parse(highWaterMarkString);
                }
                catch (FormatException)
                {
                    highWaterMark = DateTime.MinValue;
                }
                catch (Exception e)
                {
                    throw new ReaderException("feed:" + readerFeedUrl, e);
                }

                try
                {
                    Rss rss = reader.Read();

                    // TODO: Read the high water mark from db

                    foreach (RssChannelItem item in rss.Channel.Items)
                    {
                        // Ignore any items older than the highwater mark.

                        if (item.PubDate < highWaterMark)
                        {
                            continue;
                        }

                        // For each item, look for the "Nyhetsbrev" category.

                        bool publish = false;

                        foreach (RssCategory category in item.Categories)
                        {
                            if (category.Name.ToLowerInvariant() == "nyhetsbrev")
                            {
                                publish = true;
                            }
                        }


                        if (publish)
                        {
                            // Set highwater datetime mark. We do this first as a defense against mail floods, should something go wrong.

                            Persistence.Key[persistenceKey] = item.PubDate.AddMinutes(5).ToString();

                            // Verify that it was written correctly to database. This is defensive programming to avoid a mail flood.

                            if (DateTime.Parse(Persistence.Key[persistenceKey]) < item.PubDate)
                            {
                                throw new Exception(
                                          "Unable to commit new highwater mark to database in NewsletterChecker.Run()");
                            }

                            bool testMode = false;

                            if (item.Title.ToLower().Contains("test"))
                            {
                                // Newsletter blog entry contains "test" in title -> testmode
                                testMode = true;
                            }

                            // Post to forum

                            string forumText   = Blog2Forum(item.Content);
                            string mailText    = Blog2Mail(item.Content);
                            int    forumPostId = 0;
                            try
                            {
                                forumPostId = SwedishForumDatabase.GetDatabase().CreateNewPost(
                                    testMode ? ForumIdTestPost : ForumIdNewsletter, sender,
                                    "Nyhetsbrev " + DateTime.Today.ToString("yyyy-MM-dd"),
                                    item.Title, forumText);
                            }
                            catch (Exception ex)
                            {
                                if (!System.Diagnostics.Debugger.IsAttached)
                                {   // ignore when debugging
                                    throw ex;
                                }
                            }


                            // Establish people to send to, if not already done.

                            if (recipients == null || recipients.Count == 1)
                            {
                                recipients = People.FromNewsletterFeed(NewsletterFeed.TypeID.ChairmanBlog);
                            }

                            /*
                             *  Disabled sending to activists -- this was done leading up to the election in 2009
                             */
                            // Add activists (HACK)
                            // Should probably be better to select by organization, not geography.

                            /*
                             * People activists = Activists.FromGeography(Country.FromCode("SE").Geography).People;
                             *
                             * recipients = recipients.LogicalOr(activists);*/


                            // OVERRIDE: If this is a TEST newsletter, send ONLY to the originator

                            if (testMode)
                            {
                                recipients  = People.FromSingle(sender);
                                item.Title += " [TEST MODE]";
                            }

                            //TODO: hardcoded Org & geo ... using PP & World
                            Organization org = Organization.PPSE;
                            Geography    geo = Geography.Root;


                            NewsletterMail newslettermail = new NewsletterMail();

                            newslettermail.pSubject      = item.Title;
                            newslettermail.pDate         = DateTime.Now;
                            newslettermail.pForumPostUrl =
                                String.Format("http://vbulletin.piratpartiet.se/showthread.php?t={0}", forumPostId);
                            newslettermail.pBodyContent = Blog2Mail(item.Content);
                            newslettermail.pOrgName     = org.MailPrefixInherited;


                            OutboundMail newMail = newslettermail.CreateOutboundMail(sender, OutboundMail.PriorityLow, org, geo);

                            int recipientCount = 0;
                            foreach (Person recipient in recipients)
                            {
                                if (!Formatting.ValidateEmailFormat(recipient.Mail) ||
                                    recipient.MailUnreachable ||
                                    recipient.NeverMail)
                                {
                                    continue;
                                }
                                ++recipientCount;
                                newMail.AddRecipient(recipient, false);
                            }

                            newMail.SetRecipientCount(recipientCount);
                            newMail.SetResolved();
                            newMail.SetReadyForPickup();
                        }
                    }
                }
                finally
                {
                    reader.Close();
                }
            }
            catch (Exception ex)
            {
                lock (feedErrorSignaled)
                {
                    if (!feedErrorSignaled.ContainsKey(readerFeedUrl) || feedErrorSignaled[readerFeedUrl].AddMinutes(60) < DateTime.Now)
                    {
                        feedErrorSignaled[readerFeedUrl] = DateTime.Now;
                        throw new ReaderException("NewsletterChecker got error " + ex.Message + "\n when checking feed:" + readerFeedUrl + "\n(feed will be continually checked, bu will not signal error again for an hour)", ex);
                    }
                }
            }
        }
Esempio n. 13
0
        public static void SendChangeOrgMail(Person person, Membership membership, Organization newOrg)
        {
            // HACK for UPSE
            // This is a hack for the Swedish structure.

            ChangeOrgMail changeorgmail = new ChangeOrgMail();

            Organization topOrg        = Organization.FromIdentity(Organization.UPSEid);
            Organization lowOrg        = membership.Organization;
            DateTime     currentExpiry = membership.Expires;


            DateTime newExpiry = DateTime.Today.AddYears(1);


            changeorgmail.pCurrentOrg = lowOrg.Name;
            changeorgmail.pCurrentGeo = person.Geography.Name;
            changeorgmail.pNextDate   = newExpiry;

            string tokenBase = person.PasswordHash + "-" + membership.Identity.ToString() + "-" + currentExpiry.Year.ToString();

            if (newOrg.AnchorGeographyId == Geography.RootIdentity && newOrg.AutoAssignNewMembers)
            {//Fallback org
                changeorgmail.pNoLocalOrg = newOrg.Name;
                changeorgmail.pChangeOrg  = "";
            }
            else
            {
                changeorgmail.pNoLocalOrg = "";
                changeorgmail.pChangeOrg  = newOrg.Name;
            }

            if (lowOrg.AcceptsMembers)
            {
                changeorgmail.pInactiveOrg    = "";
                changeorgmail.pInactiveEnding = " ";
            }
            else
            {
                changeorgmail.pInactiveOrg = newOrg.Name;
            }



            changeorgmail.pStdRenewLink = "https://pirateweb.net/Pages/Public/SE/People/MemberRenew.aspx?PersonId=" +
                                          person.Identity.ToString() + "&Transfer=" + lowOrg.Identity.ToString() + "," +
                                          newOrg.Identity.ToString() +
                                          "&MembershipId=" + membership.Identity.ToString() +
                                          "&SecHash=" + SHA1.Hash(tokenBase + "-Transfer" + lowOrg.Identity.ToString() + "/" +
                                                                  newOrg.Identity.ToString()).Replace(" ", "").Substring(0, 8);

            OutboundMail mail = changeorgmail.CreateFunctionalOutboundMail(MailAuthorType.MemberService, OutboundMail.PriorityNormal, topOrg, Geography.Root);
            string       test = mail.RenderHtml(person, person.PreferredCulture);

            test = mail.RenderText(person, person.PreferredCulture);

            if (mail.Body.Trim() == "")
            {
                throw new InvalidOperationException("Failed to create a mailBody");
            }
            else
            {
                //mail.AddRecipient(7838, true);
                mail.AddRecipient(person.Identity, false);
                mail.SetRecipientCount(1);
                mail.SetResolved();
                mail.SetReadyForPickup();
            }
        }
Esempio n. 14
0
        public static void SendReminderMail(Membership membership)
        {
            // First, determine the organization template to use. Prioritize a long ancestry.

            // This is a hack for the Swedish structure.

            ReminderMail remindermail = new ReminderMail();

            // NEW December 2010: Organizations are separated as per common agreement, there are no common reminder mails. Every membership renews on its own.

            Organization lowOrg        = membership.Organization;
            DateTime     currentExpiry = membership.Expires;
            Person       person        = membership.Person;


            DateTime newExpiry = currentExpiry;

            //do not mess with lifetime memberships (100 years)
            if (newExpiry < DateTime.Today.AddYears(10))
            {
                newExpiry = newExpiry.AddYears(1);
            }

            remindermail.pPreamble = "<p> Nu är det dags att <strong>förnya ditt medlemskap</strong> i " + membership.Organization.Name + ".";

            remindermail.pExpirationDate = currentExpiry;
            remindermail.pNextDate       = newExpiry;
            remindermail.pOrgName        = membership.Organization.MailPrefixInherited;


            string tokenBase = person.PasswordHash + "-" + membership.Identity.ToString() + "-" + currentExpiry.Year.ToString();

            // REMOVED DEC2010: suggestion that people older than 25 may leave UP, as renewal mails are separated

            // HACK for UPSE:

            Organization expectedLowOrg = Organizations.GetMostLocalOrganization(person.GeographyId, Organization.UPSEid);

            if (expectedLowOrg != null && lowOrg.Inherits(Organization.UPSEid) && lowOrg.Identity != expectedLowOrg.Identity)
            {
                // Is this person in the wrong locale?

                remindermail.pCurrentOrg    = lowOrg.Name;
                remindermail.pOtherOrg      = expectedLowOrg.Name;
                remindermail.pGeographyName = person.Geography.Name;
                //mailBody += "Du är medlem i " + lowOrg.Name + ", men när du bor i [b]" + person.Geography.Name +
                //             "[/b] så rekommenderar " +
                //             "vi att du byter till din lokala organisation, [b]" + expectedLowOrg.Name +
                //             "[/b]. Klicka här för att göra det:\r\n\r\n";

                string link = "https://pirateweb.net/Pages/Public/SE/People/MemberRenew.aspx?PersonId=" +
                              person.Identity.ToString() + "&Transfer=" + lowOrg.Identity.ToString() + "," +
                              expectedLowOrg.Identity.ToString() +
                              "&MembershipId=" + membership.Identity.ToString() +
                              "&SecHash=" + SHA1.Hash(tokenBase + "-Transfer" + lowOrg.Identity.ToString() + "/" +
                                                      expectedLowOrg.Identity.ToString()).Replace(" ", "").Substring(0, 8);
                remindermail.pOtherRenewLink        = link;
                remindermail.pTooOldForYouthOrgSpan = " "; //clear the other span

                //mailBody += "[a href=\"" + link + "\"]" + link + "[/a]\r\n\r\n" +
                //            "Det är naturligtvis inget krav, utan du kan fortsätta precis som förut om du vill. " +
                //            "För att fortsätta i dina befintliga föreningar, klicka här:\r\n\r\n";
            }

            else
            {
                remindermail.pTooOldForYouthOrgSpan = " "; //clear the other span
                remindermail.pWrongOrgSpan          = " "; //clear the other span
                //mailBody += "Klicka på den här länken för att förnya för ett år till:\r\n\r\n";
            }

            string stdLink = "https://pirateweb.net/Pages/Public/SE/People/MemberRenew.aspx?PersonId=" +
                             person.Identity.ToString() +
                             "&MembershipId=" + membership.Identity.ToString() +
                             "&SecHash=" + SHA1.Hash(tokenBase).Replace(" ", "").Substring(0, 8);

            remindermail.pStdRenewLink = stdLink;
            tokenBase = person.PasswordHash + "-" + membership.Identity.ToString();
            string terminateLink = "https://pirateweb.net/Pages/Public/SE/People/MemberTerminate.aspx?MemberId=" +
                                   person.Identity.ToString() +
                                   "&SecHash=" + SHA1.Hash(tokenBase).Replace(" ", "").Substring(0, 8) +
                                   "&MID=" + membership.Identity.ToString();

            remindermail.pTerminateLink = terminateLink;

            //mailBody += "[a href=\"" + stdLink + "\"]" + stdLink + "[/a]\r\n\r\n" +
            //            "[br]Välkommen att vara med oss i [b]ett år till![/b]\r\n\r\n" +
            //            "Hälsningar,[br]Medlemsservice\r\n\r\n"; // +

            /*"PS: [b]Du fick ett likadant mail alldeles nyss. Om du har å, ä eller ö i ditt namn fungerade " +
             *  "inte länken i det mailet. Tack till alla som hörde av sig om det; felet är fixat nu och länken ovan ska fungera.[/b]\r\n\r\n";*/

            //OutboundMail mail = remindermail.CreateOutboundMail(sender, OutboundMail.PriorityNormal, topOrg, Geography.Root);
            OutboundMail mail = remindermail.CreateFunctionalOutboundMail(MailAuthorType.MemberService, OutboundMail.PriorityNormal, membership.Organization, Geography.Root);

            if (mail.Body.Trim() == "")
            {
                throw new InvalidOperationException("Failed to create a mailBody");
            }
            else
            {
                mail.AddRecipient(person.Identity, false);
                mail.SetRecipientCount(2);
                mail.SetResolved();
                mail.SetReadyForPickup();
            }
        }