20,173 Matching Annotations
  1. Jan 2023
    1. But it does not work, because the association with authors will return empty authors for the Material as the materials are also soft deleted.
    2. The problem is that Globalize knows nothing about acts_as_paranoid. You can delete a Material, and it should delete the translations, but when you try to recover the Material then there is an error because of how the translations are implemented and the order in which the translations and the Material are recovered. Which record should be recovered first?
    3. Remember that the Material has all of its translations for the title in a table that just got soft deleted. So the correct answer is “nil”. The title of the delete material is nil.
    4. You can workaround this with material.translations.with_deleted.where(locale: I18n.locale).first.title But this is quite ugly.
    1. check the Subject Line Preview tool to preview your email subject line on a variety of clients

      e-mail subject lines

  2. Dec 2022
    1. Breaking other user's YAML overrides is not a big deal as long as this was clearly stated in the docs and the version number is bumped accordingly.
    1. 2. Use a preference center The best way to know what topics your subscribers care about and how frequently they want to hear from your brand is to ask them. Create an email preference center so when an individual goes to subscribe to your email list, they have the power to opt-in and out of specific forms of communication. For example, maybe an individual only wants to know when you’re having sales but doesn’t care to receive your monthly newsletter and weekly marketing emails. The preference center allows them to self-select which of these emails they receive, allowing you to send more targeted emails without pestering your recipients.

      .

    1. I was thinking this morning how House Church is much like a wagon train going across the wilderness. By the time you get to your destination, you know everything about everyone on that train. You help each other and protect each other and become bonded together. The institutional church is like a high-speed bullet train. It's more comfortable, more efficient and takes you the same distance in a shorter amount of time. Also you have barely enough time to get acquainted with 1 or 2 people.
    2. For those who can hear. When you name you divide. There is zero biblical precedent for naming a certain group of believers .... Identify with the body of Christ in your area .... We are exhorted to, "let there be no division among you".The only use of "churches" plural in scripture refers to the church in different locations. There was no such thought of "churches" within one locality. Love you all and pray more will see this so the world may see we are one and know that Jesus was sent by the Father.It's important John 17:20-23
    3. no need any name whatsoever bro It's who we are that's important.
    4. Often it helps to have the location or region in the name, a mountain near you or the name of the valley you are in, or a creek, stream or river. What says 'home' about where you are?
    5. Pleeaasse don't give "it" a name.There is no "it". You believers are part of the church in your location and you meet together.There is zero biblical precedent for a group of believers giving their particular group a name.I understand that nearly all believers do .... That in no way makes it right.Names seperate us from others of the church in our area.
    6. Paul TrosclairHow is it biblical to name a church ?2wBeth BalmesPaul Trosclair geographical. E.g.Church in Corinth. Church in Ephesus.2wJohanna WhittakerBeth Balmes .. Paul's letters were to the CHURCHES (ekklesia) in ...
    7. If you practice the error of "We are of Paul", or "We are of Apollos" , that's rank heresy.
    1. whereas division implies separation (“portion,” “piece,” “unit”) diversity implies variety within a whole (“assortment,” “heterogeneity”)
    2. But, like the British before us, the Russian Czar, or the Weimar Republic, who can define where revolution originates? They all had at least one thing in common: they were all caught by surprise.

      .

    3. I once had a cut on my arm. Someone asked me, is it serious? “It depends,” I replied, “on how much I scratch.”
    1. In essentials, unity; in non-essentials, liberty; in all things, charity (kindness). Now we may not even agree about what the essentials are, but the key, I think, is that last bit – in all things, charity. Hold a generous heart for all, whether they agree with you or disagree with you.
    1. 4NO POSTING OR UPLOADING VIDEOS OF ANY KINDTo protect the quality of our group & prevent members from being solicited products & services - we don't allow any videos because we can't monitor what's being said word for word. Written post only.

      annotation meta: may need new tag: - can't effectively monitor

    2. 3NO SELF PROMOTION, RECRUITING, OR DM SPAMMINGMembers love our group because it's SAFE. We are very strict on banning members who blatantly self promote their product or services in the group OR secretly private message members to recruit them.
    3. 2NO POST FROM FAN PAGES / ARTICLES / VIDEO LINKSOur mission is to cultivate the highest quality content inside the group. If we allowed videos, fan page shares, & outside websites, our group would turn into spam fest. Original written content only
    4. 1NO POSTING LINKS INSIDE OF POST - FOR ANY REASONWe've seen way too many groups become a glorified classified ad & members don't like that. We don't want the quality of our group negatively impacted because of endless links everywhere. NO LINKS
    1. Web and mobile apps, SPAs, and SAAS products with thoughtful UX and robust implementation.
    1. Anyway, through that process, we were able to see just how many competing priorities we had as an organization, and that we needed to stop testing the waters and actually commit to one specific direction.
    1. Since there is no measurable performance advantage for either, any time (however marginal) spent thinking or talking about a choice between the two is wasted. When you prefer single quoted strings, you have to think when you need interpolation. When you use double quoted strings, you never have to think. (I'd also add, anecdotally, that apostrophes are more prevalent in strings than double quotes, which again means less thinking when using double-quoted strings.) Therefore always using double-quoted strings results in the least possible wasted time and effort.
    1. In this case, if the constant Admin::User was already loaded at the time Admin::UserManager.all was called, then it would return Admin::User objects.However, if Admin::User was not yet auto-loaded, but User was, Admin::UserManager.all would instead return User objects!
    1. That may be fine, but if you prefer you can also pass overrides to the inflectors used by the autoloaders: # config/initializers/zeitwerk.rb Rails.autoloaders.main.inflector.inflect("vat" => "VAT") Copy With this option you have more control, because only files called exactly vat.rb or directories exactly called vat will be inflected as VAT. A file called vat_rules.rb is not affected by that and can define VatRules just fine. This may be handy if the project has this kind of naming inconsistencies.
    1. I assume that the goal of synchronizing timestamps is so that the primary record and its Version can be correlated by future reporting queries. I've always thought this is an odd feature, given that said correlation can be more reliably and performantly achieved by use of the foreign key (item_id). So, I'd like to suggest that we add an option to disable this feature. For the new option's name, I'll suggest synchronize_version_creation_timestamp. It would be true by default. has_paper_trail(synchronize_version_creation_timestamp: false) I'm open to disabling this feature by default, in a future major release, after a reasonable deprecation period.
    1. GET if to obtain information. There should not be any "body" data sent with that request. This will not trigger error, but we just simply don't look there in GET request. Only query string parameters ale allowed. This request will never change anything, you can call it as many times as you want. It is called that GET is IDEMPOTENT request. POST is to add new or modify existing information. If request url doesn't contain resource ID then we will treat that as new data that must be inserted. If you want to modify existing data you need to specify an ID in the Rrequest URL (like POST /contacts/hg5fF). POST is NOT IDEMPOTENT, you need to be carefull to not send the same request twice... DELETE is only to remove infomration. As a general rule we do not allow to add any "body" data to that type of request nor we allow any query string. This should be just simply DELETE /contacts/hg5fF.
    1. Our API v3 uses the terminology from the previous version of GetResponse. Campaigns and lists are the same resource under a different name. For now, please refer to lists as campaigns. Our API v4 will use the updated terminology.
    2. You can filter the resource using criteria specified as query[*]. You can provide multiple criteria, to use AND logic. You can sort the resource using parameters specified as sort[*]. You can specify multiple fields to sort by.
    3. Enum:"add" "delete" An additional flag parameter with the value add will add masks provided in the request body to the list. A flag value delete will delete masks from the list. If there's no parameter provided, masks are replaced.
    1. I'm glad this isn't a lego set because it would cost you an arm, a leg, a nose, a kidney, your children, your siblings, your siblings-in-law, a boat, a lot of money, the London Borough of Haringey, the Eiffel Tower, your 1st cousins, a pool, Poole, a guy named Paul, Long Island, your life savings, nuclear launch codes, another lego set, thirteen domestic cats (Scottish Fold), most of your house, Birmingham, AL, your daily income, everyone who died in the Napoleonic Wars, $30,000,000,000,000,000,000,000,000,000 and £30,000,000,000,000,000,000,000,000,000, Zimbabwe, Lesotho, Angola, Namibia, Ethiopia, Mauritania, Canada, Cuba, Jamaica, The Bahamas, Georgia (country), Georgia (US state), every single person from Bosnia and Herzegovina and your time. Luckily, it doesn't.
    1. Simplify network topology by connecting only one end-device to the TP-Link device. DO NOT connect any other devices like modem or server because those may have an impact on the running of web-based management server of the TP-Link or your end-device.
    1. This is a terrible idea. At least if there's no way to opt out of it! And esp. if it doesn't auto log out the original user after some timeout.

      Why? Because I may no longer remember which device/connection I used originally or may no longer have access to that device or connection.

      What if that computer dies? I can't use my new computer to connect to admin UI without doing a factory reset of router?? Or I have to clone MAC address?

      In my case, I originally set up via ethernet cable, but after I disconnected and connected to wifi, the same device could not log in, getting this error instead! (because different interface has different mac address)

    1. It is possible to use values defined via v: option or X-Mailgun-Variables in your templates. However if you do so, the variables are included in the delivered message via the X-Mailgun-Variables header. If this is not desired, use the t:variables option or X-Mailgun-Template-Variables header instead.

      Why are they included in a header? Indeed that is not desired. So why not just not do that? Why is it different if you use t:variables? Why the inconsistency?

    2. To help you better understand the configuration possibilities and potential issues, take a look at the following table. Take into account the type of threat you are concerned with when making your decision on how to configure sending settings.
    1. When configuring SMTP settings in an after_initialize block, the settings aren't picked up by ActionMailer. This leads to runtime errors, since ActionMailer tries the default settings.
    2. This still seems like a bug, as the expected behavior doesn't occur and it's difficult (for someone unfamiliar with the inner workings of ActionMailer) to debug. I spent a good half an hour figuring out the work around, so I'm trying to prevent others from experiencing the same thing.
    1. YAML parsing is normally considered hard (complicated as the syntax is complex). With all due respect, personally I can adhere to that in part, the YAML specification appears to be at (isolated) places hard to read despite me self-imagined being trained over decades into reading publicly available specifications (in not my first language). To be fair, it is one of the very few specs that has graphics and by the nature of its formulation, compilers are hard to read as well.
    2. JSON is a similar, perhaps even more popular, format (and almost[!] a subset of YAML 1.2).

      almost eh?

    1. Compose V2 has been re-written in Go, which improves integration with other Docker command-line features, and allows it to run natively on macOS on Apple silicon, Windows, and Linux, without dependencies such as Python.
    2. Introduction of the Compose specification makes a clean distinction between the Compose YAML file model and the docker-compose implementation.
    1. While this offers flexibility to address many operator use cases, it makes simple use cases, like the developer use case, more complicated to express than they need to be.

      annotation meta: may need new tag: - developer use case - more complicated to express than they need to be.

    2. Projects like Kompose or Okteto Stacks show how the simpler Compose model can be translated into Kubernetes API payloads
    3. platform-agnostic
    4. make the Compose file the source of truth for development and deployment
    1. This variable supports multiple Compose files separated by a path separator (on Linux and macOS the path separator is :, on Windows it is ;). For example: COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml.
    2. The path separator can also be customized using COMPOSE_PATH_SEPARATOR.
    1. the main feature I miss is to be able to declare abstract services (that should never be runned but could be used to group common properties of services for convenience).
    2. I understand that multiple -f options fits almost the bill, but it doesn't always work. For example, I rather often change the name of the abstract service into something that is more meaningful in the context of the project at hand. This is something that the overriding that occurs with multiple -f options does not support.
    3. I understand that multiple -f options fits almost the bill, but it doesn't always work. For example, I rather often change the name of the abstract service into something that is more meaningful in the context of the project at hand. This is something that the overriding that occurs with multiple -f options does not support. I would not mind loosing the exact extends though, as long as their is some other way to "instantiate" an abstract service in a file.
    4. # Due to lack of "expressivity" in Compose, we define our own couple of service # "pseudo-types": # # - image-only services (name: *-image) # # The only goal of these is to build images. No other services build images. # # These have entrypoint overridden to exit immediately. # # - base services (name: *-base) # # These contain common configuration and are intended to be extended. # # Their command (not entrypoint, to keep the original one) is overridden to # exit immediately. Service must support a command to exit immediately. # # - task services (name: *-task) # # These are intended for running one-off commands. # # Their default command is overridden to exit immediately. Service must # support a command to exit immediately. # # - "real" services # # These are actual services that stay up and running.
    1. Flatpaks are comfortable for users. It does not matter if you're on Debian, Linux Mint or Fedora. It won't break your system as aplications eg. from ppas etc. Distributions are not coming with updates of Audacity, so installations of it are a big problem. Flatpaks solve it...
    2. I have yet to see a Snapd or Flatpak build of Audacity that I'm happy with. Those builds are beyond our control as they are made by 3rd parties. I do find it mildly annoying that Flatpak direct users that have problems with their builds to us.

      annotation meta: may need new tag: the runaround?

    1. Indeed, but the proliferation of general purpose keyboards with OS/2 logo keys has never come to pass... I think most of the keys are either windoze or half-eaten apples...
    1. It could also just be for clarity’s sake, since truck could mean a pick-up truck (or some other type of truck), and tractor could refer to a farm tractor (or some other type of tractor).

      Calling it a semi-truck disambiguates since "truck" and "tractor" are too ambiguous.

    1. We can’t tell you exactly who your administrator is. But here are ideas of who to ask.

      We can’t tell you...

    1. interval values can be written using the following verbose syntax: [@] quantity unit [quantity unit...] [direction] where quantity is a number (possibly signed); unit is microsecond, millisecond, second, minute, hour, day, week, month, year, decade, century, millennium, or abbreviations or plurals of these units
    1. has_scope :category do |controller, scope, value|  value != 'all' ? scope.by_category(value) : scope end
    2. Note: it is not possible to apply a boolean scope with just the query param being present, e.g. ?active, that's not considered a "true" value (the param value will be nil), and thus the scope will be called with false as argument. In order for the scope to receive a true argument the param value must be set to one of the "true" values above, e.g. ?active=true or ?active=1.

      Is this behavior/limitation part of the web standard or a Rails-specific thing?

    1. Let’s say, you’ve set up the list-unsubscribe header to you email campaign. Check out whether it works by sending an email to a test inbox. For Gmail, you’ll see the unsubscribe option in the header right next to the sender name
    2. Also, make sure a user does not need to enter credentials or select a checkbox to complete the unsubscription process.
    3. With the http method, behind the list-unsubscribe header, there is a URL leading to a web page for opting out. When a user clicks the unsubscribe link, a landing page opens, and the user is asked to confirm unsubscription.
    4. Imagine what happens when subscribers change activities, interests, or focus. As a result, they may no longer be interested in the products and services you offer. The emails they receive from you are now either ‘marked as read’ in their inbox or simply ignored. They neither click the spam reporting button nor attempt to find the unsubscribe link in the text. They are no longer your customers, but you don’t know it.
    5. Let’s say the recipient is considering unsubscribing. He or she may be too busy to search through the email to find the unsubscribe link, so he or she just clicks “Report as SPAM” to stop the emails from coming. This is the last thing any marketer wants to see happen. It negatively impacts sender reputation, requiring extra work to improve email deliverability. With the list-unsubscribe header, you will avoid getting into this kind of trouble in the first place.
    1. Easy to scan and understand what’s discussed in the space. Fewer distractions to help you focus on topics you care about. Easy to browse topics because they’re all in one place in the thread navigation panel. Thread replies don’t interrupt the main conversation. You can toggle history on and off.
    2. You can find some benefits and limitations of each kind of space organization below.
    1. The only negative to this method is that it may not ALWAYS work. If the data is faulty, or the link is inaccurately provided by the sender, Gmail won’t be able to recognise and include the unsubscribe button in Gmail.
    2. Most mailing list providers will encourage you to insert a mailto and URL within the header of your emails, or they will be automatically provided.
    3. You may find this link isn’t available straight away, after a few emails one should appear, this is a common technique with mailing list providers.
    4. and the link sometimes isn’t always supported by Gmail

      Any link should work just fine, shouldn't it?

    1. Email addresses sometimes get reassigned to a different person. For example, employment changes at a company can cause an address used for an ex-employee to be assigned to a new employee, or a mail service provider (MSP) might expire an account and then let someone else register for the local-part that was previously used. Those who sent mail to the previous owner of an address might not know that it has been reassigned. This can lead to the sending of email to the correct address but the wrong recipient. This situation is of particular concern with transactional mail related to purchases, online accounts, and the like.
    2. This can lead to the sending of email to the correct address but the wrong recipient.
    1. Errors-To is deprecated, so mail servers will typically ignore this header - most servers will bounce will to the 'envelope sender'. This is the email address that your mail client sends as part of the connection to the SMTP server (not necessarily the From address - though it typically is the same).
    1. This is where ngrok comes into play. It’s a free tool that you can download and run on your dev box. They describe themselves as a secure tunnel to localhost, and it’s just that. It’s as simple as running ngrok http 3000 to forward port 3000 (or any port) to a public ngrok address.

      ngrok

    2. goto
    3. It’s as simple as running ngrok http 3000 to forward port 3000 (or any port) to a public ngrok address.

      We're not forwarding local port 3000 to a public ngrok address — we're doing it in the opposite direction, as the previous sentence just (correctly) stated:

      a secure tunnel to localhost

    4. You can get around this by forwarding your web server’s port on your router and then use your public IP address as the webhook URL but that’s super annoying, exposes your public IP address and it will very likely change because most home grade cable / DSL connections have dynamic IP addresses.Not only that, but some services require that you respond to webhooks over HTTPS, so now you would be responsible for setting up HTTPS too, when really all you want to do is test a webhook in development.
    5. Webhooks are a really powerful concept. They let you integrate with third party services in a very easy way and you can do it without having to constantly pull information from a service.
    1. Postmark separates email traffic through Message Streams, meaning that transactional and broadcast traffic never intersects in Postmark, including IP ranges. This is a longstanding best practice for ensuring optimal deliverability. Transactional message streams are for messages that are usually unique and triggered by a user action like a password reset, opted-into weekly digest, or receipts. Transactional streams do not support bulk messages. Broadcast message streams are for bulk messages that sent to multiple recipients at once like announcements, newsletters, or other application email.
    2. API TypeMailgun API NamePostmark API NameSending EmailsMessagesEmailManaging SuppressionsSuppressionsSuppressionsManaging TemplatesTemplatesTemplatesManaging Sending SettingsServerManaging ServersServersManaging Sent EmailsEventsMessagesManaging Inbound EmailsMessages, EventsMessagesManage Inbound Processing SettingsRoutesManage email domains you can send fromDomainsDomains
    1. The best at transactional email because we never let them mix with bulk messages. You might say that Postmark has serious street cred with inbox providers. To protect the delivery of your transactional emails, it’s crucial to separate them from your bulk or promotional emails. With Message Streams, we’ve built a parallel but completely separate sending infrastructure for these two different types of emails. We don’t let them mix. Ever.
    1. I like how they show -18% -30% over 12-month and 24-month so you can see your savings reward for making longer commitments.

    1. Before, you could send unlimited emails to your lists. This was a huge positive for MailChimp, and it attracted tens of thousands of new customers. Now, they have set limits in an attempt to force users to upgrade. It makes dollar and cents but doesn’t make common sense. It’s alienating a lot of users and hurting their reputation.
    2. Now, they charge by a new metric: audiences. And your audiences also include unsubscribed emails! So, even if someone in your list has unsubscribed, they are still counted in your audience.
    1. With Mailgun, you'll need to upgrade to a dedicated IP or "managed email service" and pay extra for "better deliverability." At Postmark, great deliverability isn't an up-charge. It's simply included, and we share live delivery data so you can judge for yourself.
    1. We will also run into some issues when we consider adding new channels to Service Desk like an API. We should have a streamlined process of rendering notes (messages) etc. Having a base64 image (or even attachment) in mail but not in the API might be inconsistent and also adds a lot of code that needs to be maintained.
    1. Dilemma: Do I use this unofficial library with its really nice idiomatic API or the official library (https://github.com/mailgun/mailgun-ruby) with its inferior API?

      I wish this one was still/better maintained because I'd much rather use this API, like: @mailgun.lists.create "devs@your.mailgun.domain" @mailgun.lists.list @mailgun.lists.find "devs@your.mailgun.domain"

      but it's not maintained, and looks like it doesn't have the word events in the source at all, so it's missing any way to use the Events API. :(

    1. Include one or both of these headers in your messages:

      Actually, if you include List-Unsubscribe-Post, then you MUST include List-Unsubscribe (both).

      According to https://www.rfc-editor.org/rfc/rfc8058#section-3.1,

      A mail sender that wishes to enable one-click unsubscriptions places one List-Unsubscribe header field and one List-Unsubscribe-Post header field in the message. The List-Unsubscribe header field MUST contain one HTTPS URI. It MAY contain other non-HTTP/S URIs such as MAILTO:. The List-Unsubscribe-Post header MUST contain the single key/value pair "List-Unsubscribe=One-Click".

    2. List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: <https://solarmora.com/unsubscribe/example>
    3. Here are some recommended unsubscribe methods: Include a prominent link in the message that takes recipients to a page for unsubscribing. Let recipients review the individual mailing lists they’re subscribed to. Let them unsubscribe from lists individually, or all lists at once. Automatically unsubscribe recipients who have multiple bounced messages. Periodically send a confirmation message to recipients to make sure they still want to get your messages.
    4. Let recipients easily unsubscribe Always give recipients a way to unsubscribe from your messages. Make unsubscribing easy. Letting people opt out of your messages can improve message open rates, click-through rates, and sending efficiency.
    5. Make sure recipients can easily subscribe
    6. This article was previously called Bulk sender guidelines.
    1. But anti- spam software often fetches all resources in mail header fields automatically, without any action by the user, and there is no mechanical way for a sender to tell whether a request was made automatically by anti-spam software or manually requested by a user. To prevent accidental unsubscriptions, senders return landing pages with a confirmation step to finish the unsubscribe request. A live user would recognize and act on this confirmation step, but an automated system would not. That makes the unsubscription process more complex than a single click.

      HTTP: method: safe methods: GETs have to be safe, just in case a machine crawls it.

    2. Many mail systems allow recipients to report mail as spam or junk, and mail streams from senders whose mail is often reported as junk tend to have poor deliverability. Hence, the mailers want to make it as easy as possible for recipients to unsubscribe; if an unsubscription process is too difficult, the recipient's alternative is to report mail from the sender as junk until the mail no longer appears in the recipient's inbox.
    3. Operators of recipient mail systems are aware that their users do not make a clear distinction between unsubscription and junk.
    4. The target of the POST action is the same as the one in the GET action for a manual unsubscription, so this is intended to allow the same server code to handle both.
    5. The mail sender MUST NOT return an HTTPS redirect, since redirected POST actions have historically not worked reliably, and many browsers have turned redirected HTTP POSTs into GETs.
    6. This specification provides a way for recipient systems to notify the mailer automatically, using only information within the mail message, and without prearrangement.
    7. This document describes a method for signaling a one-click function for the List-Unsubscribe email header field. The need for this arises out of the actuality that mail software sometimes fetches URLs in mail header fields, and thereby accidentally triggers unsubscriptions in the case of the List-Unsubscribe header field.
    1. If a contact ever reaches out and is no longer receiving messages because they accidentally marked one of your campaigns as spam, you can reach out to Product Support. We can remove them from the suppression list for you. 

      why not allow user to do it directly instead of force to contact support? If they'll remove it for you because you said the user asked you to... why not just let you remove the suppression yourself? Mailgun lets you directly delete suppressions via their API.

    2. For compliance reasons, you will not be able to see contacts who submit spam complaints in your exclusion list.  We do not offer the ability to export a list of spam complaints from FBLs at the moment. This is also for compliance. 

      "For compliance reasons". That's pretty vague. Compliance with what?

    1. Information is blocked from going outside the organization when data is not supposed to leave the tenant boundary for compliance purposes (for example, in U.S. Government organizations: Microsoft 365 GCC, GCC High, and DoD). Reporting a message or file to Microsoft from one of these organizations will have the following message in the result details: Further investigation needed. Your tenant does not allow data to leave the environment, so we could not find anything with an initial scan. You'll need to contact Microsoft support to have this item reviewed.

      seemingly contradictory:

      You'll need to contact Microsoft support to have this item reviewed. But they already tried to report it to Microsoft and it was blocked? What form of contacting Microsoft support is expected to be used and how is it better? Won't any form of "having this item reviewed" cause it to leave the boundary and go outside the organization?

    2. Submit false positives (good email that was blocked or sent to junk folder) and false negatives (unwanted email or phish that was delivered to the inbox)

      They got it correct. Good!

    1. Can't annotate on https://feedback.mailgun.com/forums/156243-feature-requests/suggestions/39905227-provide-meaningful-delivery-status-description-rat so posting here instead.

      Anonymous commented · May 26, 2021 4:36 AM

      Without your comment I'd never find the real issue, because I was only look at permanent failures. That error message is really misleading, hope they can fix this.

      Kelly commented · December 30, 2020 2:35 AM

      Yes we desperately need this too. Half of our recipients were soft bounced due to "Too old" but we could still send to them previously on other ESPs.

    2. Certain email servers, Yahoo especially, throttle deliveries when multiple inbound is detected from the same IP. When this happens, Mailgun sends a "temporary" severity bounce. Mailgun will continue to retry over a period of time. If it can't deliver after 8 hours. The email will permanently fail with severity: permanent and reason: old.
    3. Just to add that there is also reason: old. This happens when email cannot be delivered after 8 hours. It should still be treated as a non permanent bounce though.
    4. Adding a condition to ensure that a contact is marked as bounced only if the reason is one of the above, should hopefully resolve this issue.
    5. I did some further digging and found that there is a reason property that can be used to determine whether Mailgun added an email address to its bounce suppression list:
    6. ...but even repeated soft bounces is a message level event, not one that means there will never be an opportunity to deliver to this address again. Hence Mailgun itself not adding this to their permanent uppression list..but that implies, right, that they will send to the permanent failure hook in this case?

      That could be a problem, if it actually send to the permanent failure hook in this case. Then you would have to hit their bounces API to check whether it's actually a permanent failure / hard bounce for the recipient as opposed to just for this message.

    7. From that quote above, it is clear Mailgun recognise this issue themselves (the possibility of one-off soft bounces for a variety of reasons) and therefore do not add these contacts to their permanent bounce list - unless its a true hard bounce. But they are rightly still alerting that the message in question has permanently failed to be delivered on this occasion.
    8. Mailgun, with its permanent failure webhook, is sending a message about a permanent failure of that specific message - it is Campaign that is then making a decision to translate this message, about just that one message, into a permanently bounced (suppressed) contact, and blocking all future emails to that contact - based on, what is clearly quite possibly just a temporary failure. It's really the distinction between a single message level (temporary) problem and a (permanent) contact level problem that is being lost with Campaign's current approach.
    9. but that before marking the contact as a bounced, Campaign should double check it was really a hard bounce that would affect future deliverability.
    10. some are legit bounces (people who typed emails wrongly etc) - but some are 'too old' which is a generic deliverability type message (according to Mailgun)

      too old error

    11. This becomes, then, a thorny problem - these perfectly valid emails, that are affected by this temporary issue - are marked as permanently bounced in Campaign...when they really shouldn't be given this bigger picture.
    12. But these are not permanent failures - they ARE permanent for that message of course

      Exactly. I arrived at the same conclusion.

    13. his is not wonderfully clear/great form Mailgun's end (as they are effectively translating a temporary delivery issues into a message about a permanent contact failure) - but the net effect is pretty broken handling of temporary bounces against contacts, which just creates inaccuracies and a bit of a mess.
    14. but really anyone using Mailgun is going to want this, aren't they?
    15. Mailgun, like all of these services at the more affordable levels, uses shared IPs for sending the mail. Unfortunately, as I have found over the last 3 or 4 years with them, it is not uncommon that one of their IPs gets blacklisted by SpamCop and similar services due to some other user of that IP being 'noisy' as Mailgun put it.
    16. Yes you could disable the Mailgun webhooks altogether as Mailgun will never allow sending to hard bounced email addresses.
  3. Nov 2022
    1. Mash duplicates any sub-Hashes that you add to it and wraps them in a Mash. This allows for infinite chaining of nested Hashes within a Mash without modifying the object(s) that are passed into the Mash. When you subclass Mash, the subclass wraps any sub-Hashes in its own class. This preserves any extensions that you mixed into the Mash subclass and allows them to work within the sub-Hashes, in addition to the main containing Mash.
    2. eierlegende Wollmilchsau
    3. foo = Foo.new(bar: 'baz') #=> {:bar=>"baz"} qux = { **foo, quux: 'corge' } #=> {:bar=> "baz", :quux=>"corge"} qux.is_a?(Foo) #=> true

      This surprised me.

      I would have expected — since Hash literal notation { } was used — that the resulting type would be Hash, not the type of foo. Strange.

      Is this a good thing... or?


      Also, in my quick test, I didn't find this to be true, so...?

      ``` main > symbol_mash.class => SymbolizedMash

      main > { **symbol_mash }.class => Hash ```

    4. by using symbols as keys, you will be able to use the implicit conversion of a Mash via the #to_hash method to destructure (or splat) the contents of a Mash out to a block

      Eh? The example below:

      symbol_mash = SymbolizedMash.new(id: 123, name: 'Rey') symbol_mash.each do |key, value| # key is :id, then :name # value is 123, then 'Rey' end

      seems to imply that this is possible (and does an implicit conversion) because it defines to_hash. But that's simply not true, as these 2 examples below prove:

      ``` main > symbol_mash.class_eval { undef :to_hash } => nil

      main > symbol_mash.each {|k,v| p [k,v] } [:id, 123] [:name, "Rey"] => {:id=>123, :name=>Rey} ```

      ``` main > s = 'a' => a

      main > s.class_eval do def to_hash chars.zip(chars).to_h end end => :to_hash

      main > s.to_hash => {a=>a}

      main > s.each Traceback (most recent call last) (filtered by backtrace_cleaner; set Pry.config.clean_backtrace = false to see all frames): 1: (pry):85:in __pry__' NoMethodError: undefined methodeach' for "a":String ```

    5. by using symbols as keys, you will be able to use the implicit conversion of a Mash via the #to_hash method to destructure (or splat) the contents of a Mash out to a block

      This doesn't actually seem to be an example of destructure/splat. (When it said "destructure the contents ... out to a block", I was surprised and confused, because splatting is when you splat it into an argument or another hash — never a block.)

      An example of destructure/splat would be more like

      method_that_takes_kwargs(**symbol_mash)

    6. It can be useful to use with keywords argument, which required symbol keys.
    7. This extension still allows indifferent access, but keeps the form of the keys to eliminate confusion when you're not expecting the keys to change.
    8. Since Mash is conceived to provide psuedo-object functionality, handling keys which cannot represent a method call falls outside its scope of value.
    9. Hashie does not have built-in support for coercing boolean values, since Ruby does not have a built-in boolean type or standard method for coercing to a boolean. You can coerce to booleans using a custom proc.

      I use: ActiveRecord::Type::Boolean.new.cast(value)

    10. Note: The ? method will return false if a key has been set to false or nil. In order to check if a key has been set at all, use the mash.key?('some_key') method instead.
    11. Mash is an extended Hash that gives simple pseudo-object functionality that can be built from hashes and easily extended. It is intended to give the user easier access to the objects within the Mash through a property-like syntax, while still retaining all Hash functionality.
    12. user.deep_fetch :groups, 1, :name

      similar to: dig

    13. Though this is a hash extension, it conveniently allows for arrays to be present in the nested structure. This feature makes the extension particularly useful for working with JSON API responses.
    14. Value coercions, on the other hand, will coerce values based on the type of the value being inserted. This is useful if you are trying to build a Hash-like class that is self-propagating.